From noreply at buildbot.pypy.org Tue Sep 1 10:08:44 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:08:44 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Move away from ExtRegistryEntries Message-ID: <20150901080844.3AE5A1C08B9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79334:d2748862570b Date: 2015-09-01 10:07 +0200 http://bitbucket.org/pypy/pypy/changeset/d2748862570b/ Log: Move away from ExtRegistryEntries diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -369,7 +369,6 @@ return None # r_dict: can throw anything return [] # else: no possible exception -# also used for objectmodel.contains_with_hash() def dict_contains(s_dct, s_element): s_dct.dictdef.generalize_key(s_element) if s_dct._is_empty(): @@ -455,6 +454,9 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + def method_clear(self): pass @@ -467,6 +469,9 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -790,53 +790,23 @@ def iterkeys_with_hash(d): """Iterates (key, hash) pairs without recomputing the hash.""" - assert not we_are_translated() # this code is only before translation - for k in d: - yield k, hash(k) + if not we_are_translated(): + if isinstance(d, r_dict): + xxx + else: + return ((k, compute_hash(k)) for k in d) + return d.iterkeys_with_hash() def contains_with_hash(d, key, h): """Same as 'key in d'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" - assert not we_are_translated() # this code is only before translation - assert hash(key) == h - return key in d - -class Entry(ExtRegistryEntry): - _about_ = iterkeys_with_hash - - def compute_result_annotation(self, s_d): - from rpython.annotator.model import SomeDict, SomeIterator, s_None - if isinstance(s_d, SomeDict): - return SomeIterator(s_d, 'keys_with_hash') - if s_None.contains(s_d): - return None - raise Exception("iterkeys_with_hash(x): x not a dict") - - def specialize_call(self, hop): - from rpython.rtyper.lltypesystem.rdict import DictIteratorRepr - hop.exception_cannot_occur() - return DictIteratorRepr(hop.args_r[0], "keys_with_hash").newiter(hop) - -class Entry(ExtRegistryEntry): - _about_ = contains_with_hash - - def compute_result_annotation(self, s_d, s_key, s_hash): - from rpython.annotator.model import s_Bool, SomeDict, s_None - from rpython.annotator.unaryop import dict_contains - if isinstance(s_d, SomeDict): - return dict_contains(s_d, s_key) - if s_None.contains(s_d): - return None - raise Exception("contains_with_hash(x, ...): x not a dict") - - def specialize_call(self, hop): - from rpython.rtyper.lltypesystem import lltype - from rpython.rtyper.lltypesystem.rdict import ll_contains_with_hash - r_dict = hop.args_r[0] - v_dict, v_key, v_hash = hop.inputargs(r_dict, r_dict.key_repr, - lltype.Signed) - hop.exception_cannot_occur() - return hop.gendirectcall(ll_contains_with_hash, v_dict, v_key, v_hash) + if not we_are_translated(): + if isinstance(d, r_dict): + xxx + else: + assert compute_hash(key) == h + return key in d + return d.contains_with_hash(key, h) # ____________________________________________________________ diff --git a/rpython/rtyper/lltypesystem/rdict.py b/rpython/rtyper/lltypesystem/rdict.py --- a/rpython/rtyper/lltypesystem/rdict.py +++ b/rpython/rtyper/lltypesystem/rdict.py @@ -871,11 +871,6 @@ i = ll_dict_lookup(d, key, d.keyhash(key)) return not i & HIGHEST_BIT -# for objectmodel.contains_with_hash() -def ll_contains_with_hash(d, key, hash): - i = ll_dict_lookup(d, key, hash) - return not i & HIGHEST_BIT - POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -335,6 +335,10 @@ hop.exception_cannot_occur() return DictIteratorRepr(self, "items").newiter(hop) + def rtype_method_iterkeys_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "keys_with_hash").newiter(hop) + def rtype_method_clear(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() @@ -358,6 +362,13 @@ v_res = hop.gendirectcall(target, *v_args) return self.recast_value(hop.llops, v_res) + def rtype_method_contains_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs(self, self.key_repr, + lltype.Signed) + hop.exception_is_here() + return hop.gendirectcall(ll_dict_contains_with_hash, + v_dict, v_key, v_hash) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -1217,6 +1228,10 @@ i = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) return i >= 0 +def ll_dict_contains_with_hash(d, key, hash): + i = d.lookup_function(d, key, hash, FLAG_LOOKUP) + return i >= 0 + def _ll_getnextitem(dic): if dic.num_live_items == 0: raise KeyError From noreply at buildbot.pypy.org Tue Sep 1 10:38:47 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:38:47 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: setitem_with_hash Message-ID: <20150901083847.E5C221C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79335:908587219ea9 Date: 2015-09-01 10:29 +0200 http://bitbucket.org/pypy/pypy/changeset/908587219ea9/ Log: setitem_with_hash diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -519,26 +519,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -16,6 +17,8 @@ from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -364,11 +367,6 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - def dict_contains(s_dct, s_element): s_dct.dictdef.generalize_key(s_element) if s_dct._is_empty(): @@ -381,7 +379,7 @@ def contains_SomeDict(annotator, dct, element): return dict_contains(annotator.annotation(dct), annotator.annotation(element)) -contains_SomeDict.can_only_throw = _can_only_throw +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -471,6 +469,11 @@ def method_contains_with_hash(self, s_key, s_hash): return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -808,6 +808,18 @@ return key in d return d.contains_with_hash(key, h) +def setitem_with_hash(d, key, h, value): + """Same as 'd[key] = value'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + if isinstance(d, r_dict): + xxx + else: + assert compute_hash(key) == h + d[key] = value + return + d.setitem_with_hash(key, h, value) + # ____________________________________________________________ def import_from_mixin(M, special_methods=['__init__', '__del__']): diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -597,8 +597,6 @@ d = {i+.0: 5, i+.5: 6} total = 0 for k, h in iterkeys_with_hash(d): - print k, h - print compute_hash(k) total += k * h total -= (i + 0.0) * compute_hash(i + 0.0) total -= (i + 0.5) * compute_hash(i + 0.5) @@ -618,6 +616,17 @@ f(29) interpret(f, [29]) +def test_setitem_with_hash(): + def f(i): + d = {} + setitem_with_hash(d, i+.5, compute_hash(i+.5), 42) + setitem_with_hash(d, i+.6, compute_hash(i+.6), -612) + return d[i+.5] + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + def test_import_from_mixin(): class M: # old-style def f(self): pass diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -369,6 +369,16 @@ return hop.gendirectcall(ll_dict_contains_with_hash, v_dict, v_key, v_hash) + def rtype_method_setitem_with_hash(self, hop): + v_dict, v_key, v_hash, v_value = hop.inputargs( + self, self.key_repr, lltype.Signed, self.value_repr) + if self.custom_eq_hash: + hop.exception_is_here() + else: + hop.exception_cannot_occur() + hop.gendirectcall(ll_dict_setitem_with_hash, + v_dict, v_key, v_hash, v_value) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -563,6 +573,10 @@ index = d.lookup_function(d, key, hash, FLAG_STORE) return _ll_dict_setitem_lookup_done(d, key, value, hash, index) +def ll_dict_setitem_with_hash(d, key, hash, value): + index = d.lookup_function(d, key, hash, FLAG_STORE) + return _ll_dict_setitem_lookup_done(d, key, value, hash, index) + # It may be safe to look inside always, it has a few branches though, and their # frequencies needs to be investigated. @jit.look_inside_iff(lambda d, key, value, hash, i: jit.isvirtual(d) and jit.isconstant(key)) From noreply at buildbot.pypy.org Tue Sep 1 10:38:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:38:50 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: getitem_with_hash Message-ID: <20150901083850.0E5921C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79336:a2de5fee1e30 Date: 2015-09-01 10:34 +0200 http://bitbucket.org/pypy/pypy/changeset/a2de5fee1e30/ Log: getitem_with_hash diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -475,6 +475,10 @@ pair(self, s_key).setitem(s_value) method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -788,23 +788,23 @@ d = d.keys() return reversed(d) +def _expected_hash(d, key): + if isinstance(d, r_dict): + xxx + else: + return compute_hash(key) + def iterkeys_with_hash(d): """Iterates (key, hash) pairs without recomputing the hash.""" if not we_are_translated(): - if isinstance(d, r_dict): - xxx - else: - return ((k, compute_hash(k)) for k in d) + return ((k, _expected_hash(d, k)) for k in d) return d.iterkeys_with_hash() def contains_with_hash(d, key, h): """Same as 'key in d'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" if not we_are_translated(): - if isinstance(d, r_dict): - xxx - else: - assert compute_hash(key) == h + assert _expected_hash(d, key) == h return key in d return d.contains_with_hash(key, h) @@ -812,14 +812,19 @@ """Same as 'd[key] = value'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" if not we_are_translated(): - if isinstance(d, r_dict): - xxx - else: - assert compute_hash(key) == h + assert _expected_hash(d, key) == h d[key] = value return d.setitem_with_hash(key, h, value) +def getitem_with_hash(d, key, h): + """Same as 'd[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + return d[key] + return d.getitem_with_hash(key, h) + # ____________________________________________________________ def import_from_mixin(M, special_methods=['__init__', '__del__']): diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -627,6 +627,15 @@ res = interpret(f, [27]) assert res == 42 +def test_getitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + return getitem_with_hash(d, i+.5, compute_hash(i+.5)) + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + def test_import_from_mixin(): class M: # old-style def f(self): pass diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -379,6 +379,16 @@ hop.gendirectcall(ll_dict_setitem_with_hash, v_dict, v_key, v_hash, v_value) + def rtype_method_getitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + v_res = hop.gendirectcall(ll_dict_getitem_with_hash, + v_dict, v_key, v_hash) + return self.recast_value(hop.llops, v_res) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -568,6 +578,13 @@ else: raise KeyError +def ll_dict_getitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_LOOKUP) + if index >= 0: + return d.entries[index].value + else: + raise KeyError + def ll_dict_setitem(d, key, value): hash = d.keyhash(key) index = d.lookup_function(d, key, hash, FLAG_STORE) From noreply at buildbot.pypy.org Tue Sep 1 10:38:52 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:38:52 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Fix iterkeys_with_hash Message-ID: <20150901083852.2751B1C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79337:23c0a1a91166 Date: 2015-09-01 10:35 +0200 http://bitbucket.org/pypy/pypy/changeset/23c0a1a91166/ Log: Fix iterkeys_with_hash diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -794,10 +794,14 @@ else: return compute_hash(key) +def _iterkeys_with_hash_untranslated(d): + for k in d: + yield (k, _expected_hash(d, k)) + def iterkeys_with_hash(d): """Iterates (key, hash) pairs without recomputing the hash.""" if not we_are_translated(): - return ((k, _expected_hash(d, k)) for k in d) + return _iterkeys_with_hash_untranslated(d) return d.iterkeys_with_hash() def contains_with_hash(d, key, h): From noreply at buildbot.pypy.org Tue Sep 1 10:38:54 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:38:54 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: the r_dict case Message-ID: <20150901083854.529FD1C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79338:e898f825312b Date: 2015-09-01 10:39 +0200 http://bitbucket.org/pypy/pypy/changeset/e898f825312b/ Log: the r_dict case diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -790,7 +790,7 @@ def _expected_hash(d, key): if isinstance(d, r_dict): - xxx + return d.key_hash(key) else: return compute_hash(key) diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -636,6 +636,24 @@ res = interpret(f, [27]) assert res == 42 +def test_rdict_with_hash(): + def f(i): + d = r_dict(strange_key_eq, strange_key_hash) + h = strange_key_hash("abc") + assert h == strange_key_hash("aXX") and strange_key_eq("abc", "aXX") + setitem_with_hash(d, "abc", h, i) + assert getitem_with_hash(d, "aXX", h) == i + try: + getitem_with_hash(d, "bYY", strange_key_hash("bYY")) + except KeyError: + pass + else: + raise AssertionError + return 0 + + assert f(29) == 0 + interpret(f, [27]) + def test_import_from_mixin(): class M: # old-style def f(self): pass From noreply at buildbot.pypy.org Tue Sep 1 10:43:06 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 1 Sep 2015 10:43:06 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: tanslation issues, removed old function Message-ID: <20150901084306.DEE081C050D@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79339:11cf3f890e18 Date: 2015-09-01 10:43 +0200 http://bitbucket.org/pypy/pypy/changeset/11cf3f890e18/ Log: tanslation issues, removed old function diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -968,12 +968,6 @@ self.coefficient_div == 1 and \ self.constant == 0 - def less(self, other): - # TODO - if self.same_variable(other): - return self.constant_diff(other) < 0 - return False - def clone(self): c = IndexVar(self.var) c.coefficient_mul = self.coefficient_mul diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -878,7 +878,6 @@ if op.casts_box(): count = pack_type.getcount() return count - count = vec_reg_size // pack_type.getsize() return count @@ -892,7 +891,7 @@ # casting is special, often only takes a half full vector pack_type = pack.input_type if pack_type is None: - pack_type = self.output_type # load operations + pack_type = pack.output_type # load operations return pack_type.byte_size() return vec_reg_size @@ -1001,6 +1000,7 @@ def slice_operations(self, vec_reg_size): count = opcount_filling_vector_register(self, vec_reg_size) + assert count > 0 newoplist = self.operations[count:] oplist = self.operations[:count] assert len(newoplist) + len(oplist) == len(self.operations) diff --git a/rpython/jit/metainterp/test/test_vectorize.py b/rpython/jit/metainterp/test/test_vectorize.py --- a/rpython/jit/metainterp/test/test_vectorize.py +++ b/rpython/jit/metainterp/test/test_vectorize.py @@ -289,27 +289,17 @@ res = self.meta_interp(f, [i]) assert res == f(i) - @py.test.mark.parametrize('i,v1,v2',[(25,2.5,0.3)]) + @py.test.mark.parametrize('i,v1,v2',[(25,2.5,0.3),(25,2.5,0.3)]) def test_list_vectorize(self,i,v1,v2): myjitdriver = JitDriver(greens = [], reds = 'auto') class ListF(object): - def __init__(self, size, init=0.0): + def __init__(self, size, init): self.list = [init] * size def __getitem__(self, key): - if key < 0: - raise IndexError - if key >= len(self.list): - raise IndexError return self.list[key] def __setitem__(self, key, value): - if key < 0: - raise IndexError - if key >= len(self.list): - raise IndexError self.list[key] = value - def append(self, value): - self.list.append(value) def f(d, v1, v2): a = ListF(d, v1) b = ListF(d, v2) From noreply at buildbot.pypy.org Tue Sep 1 10:48:20 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:48:20 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Try to use the _with_hash functions at one place for now Message-ID: <20150901084820.B1F881C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79340:95eb41256451 Date: 2015-09-01 10:48 +0200 http://bitbucket.org/pypy/pypy/changeset/95eb41256451/ Log: Try to use the _with_hash functions at one place for now diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,15 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - # xxx performance issue when compared to CPython: the next - # two lines will recompute twice the hash of 'key', whereas - # CPython reuses the hash from 'iterator' in both cases. - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): From noreply at buildbot.pypy.org Tue Sep 1 10:49:11 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 10:49:11 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: hg merge default Message-ID: <20150901084911.E5E421C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79341:2e2ff01da2a9 Date: 2015-09-01 10:49 +0200 http://bitbucket.org/pypy/pypy/changeset/2e2ff01da2a9/ Log: hg merge default diff too long, truncating to 2000 out of 16833 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -352,8 +353,7 @@ Except when otherwise stated (look for LICENSE files or copyright/license information at the beginning of each file) the files in the 'lib-python/2.7' directory are all copyrighted by the Python Software Foundation and licensed -under the Python Software License of which you can find a copy here: -http://www.python.org/doc/Copyright.html +under the terms that you can find here: https://docs.python.org/2/license.html License for 'pypy/module/unicodedata/' ====================================== @@ -435,4 +435,4 @@ The code is based on gperftools. You may see a copy of the License for it at - https://code.google.com/p/gperftools/source/browse/COPYING + https://github.com/gperftools/gperftools/blob/master/COPYING diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -308,7 +308,10 @@ if (len(data) != 8 or data[:4] != imp.get_magic() or struct.unpack(" -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include # endif #endif @@ -214,6 +214,12 @@ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py --- a/lib_pypy/cffi/api.py +++ b/lib_pypy/cffi/api.py @@ -236,6 +236,30 @@ cdecl = self._typeof(cdecl) return self._backend.newp(cdecl, init) + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + def cast(self, cdecl, source): """Similar to a C cast: returns an instance of the named C type initialized with the given 'source'. The source is @@ -286,7 +310,7 @@ """ return self._backend.from_buffer(self.BCharA, python_buffer) - def callback(self, cdecl, python_callable=None, error=None): + def callback(self, cdecl, python_callable=None, error=None, onerror=None): """Return a callback object or a decorator making such a callback object. 'cdecl' must name a C function pointer type. The callback invokes the specified 'python_callable' (which may @@ -298,7 +322,8 @@ if not callable(python_callable): raise TypeError("the 'python_callable' argument " "is not callable") - return self._backend.callback(cdecl, python_callable, error) + return self._backend.callback(cdecl, python_callable, + error, onerror) if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) if python_callable is None: @@ -327,6 +352,13 @@ data. Later, when this new cdata object is garbage-collected, 'destructor(old_cdata_object)' will be called. """ + try: + gcp = self._backend.gcp + except AttributeError: + pass + else: + return gcp(cdata, destructor) + # with self._lock: try: gc_weakrefs = self.gc_weakrefs @@ -428,6 +460,8 @@ raise TypeError("ffi.include() expects an argument that is also of" " type cffi.FFI, not %r" % ( type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") with ffi_to_include._lock: with self._lock: self._parser.include(ffi_to_include._parser) diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -989,7 +989,8 @@ def cast(self, BType, source): return BType._cast_from(source) - def callback(self, BType, source, error): + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented return BType(source, error) typeof = type diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -53,6 +53,7 @@ OP_GLOBAL_VAR = 33 OP_DLOPEN_FUNC = 35 OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 PRIM_VOID = 0 PRIM_BOOL = 1 @@ -105,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -15,9 +15,11 @@ except ImportError: lock = None -_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", - re.MULTILINE) +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") @@ -39,6 +41,7 @@ macros = {} for match in _r_define.finditer(csource): macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) # Replace "[...]" with "[__dotdotdotarray__]" @@ -423,13 +426,10 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - elif (len(params) == 1 and - isinstance(params[0].type, pycparser.c_ast.TypeDecl) and - isinstance(params[0].type.type, pycparser.c_ast.IdentifierType) - and list(params[0].type.type.names) == ['void']): - del params[0] args = [self._as_func_arg(self._get_type(argdeclnode.type)) for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] result = self._get_type(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) @@ -633,6 +633,8 @@ def include(self, other): for name, tp in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include kind = name.split(' ', 1)[0] if kind in ('struct', 'union', 'enum', 'anonymous'): self._declare(name, tp, included=True) @@ -646,10 +648,21 @@ assert typenames[-1] == '__dotdotdot__' if len(typenames) == 1: return model.unknown_type(decl.name) - for t in typenames[:-1]: - if t not in ['int', 'short', 'long', 'signed', 'unsigned', 'char']: - raise api.FFIError(':%d: bad usage of "..."' % decl.coord.line) + + if (typenames[:-1] == ['float'] or + typenames[:-1] == ['double']): + # not for 'long double' so far + result = model.UnknownFloatType(decl.name) + else: + for t in typenames[:-1]: + if t not in ['int', 'short', 'long', 'signed', + 'unsigned', 'char']: + raise api.FFIError(':%d: bad usage of "..."' % + decl.coord.line) + result = model.UnknownIntegerType(decl.name) + if self._uses_new_feature is None: self._uses_new_feature = "'typedef %s... %s'" % ( ' '.join(typenames[:-1]), decl.name) - return model.UnknownIntegerType(decl.name) + + return result diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -35,9 +35,6 @@ def is_integer_type(self): return False - def sizeof_enabled(self): - return False - def get_cached_btype(self, ffi, finishlist, can_delay=False): try: BType = ffi._cached_btypes[self] @@ -80,8 +77,7 @@ class BasePrimitiveType(BaseType): - def sizeof_enabled(self): - return True + pass class PrimitiveType(BasePrimitiveType): @@ -162,12 +158,23 @@ self.c_name_with_marker = name + '&' def is_integer_type(self): - return True # for now + return True def build_backend_type(self, ffi, finishlist): raise NotImplementedError("integer type '%s' can only be used after " "compilation" % self.name) +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + class BaseFunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') @@ -205,9 +212,6 @@ class FunctionPtrType(BaseFunctionType): _base_pattern = '(*&)(%s)' - def sizeof_enabled(self): - return True - def build_backend_type(self, ffi, finishlist): result = self.result.get_cached_btype(ffi, finishlist) args = [] @@ -233,9 +237,6 @@ extra = self._base_pattern self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) - def sizeof_enabled(self): - return True - def build_backend_type(self, ffi, finishlist): BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) return global_cache(self, ffi, 'new_pointer_type', BItem) @@ -276,9 +277,6 @@ self.c_name_with_marker = ( self.item.c_name_with_marker.replace('&', brackets)) - def sizeof_enabled(self): - return self.item.sizeof_enabled() and self.length is not None - def resolve_length(self, newlength): return ArrayType(self.item, newlength) @@ -433,9 +431,6 @@ from . import ffiplatform raise ffiplatform.VerificationMissing(self._get_c_name()) - def sizeof_enabled(self): - return self.fldtypes is not None - def build_backend_type(self, ffi, finishlist): self.check_not_partial() finishlist.append(self) @@ -464,9 +459,6 @@ self.baseinttype = baseinttype self.build_c_name_with_marker() - def sizeof_enabled(self): - return True # not strictly true, but external enums are obscure - def force_the_name(self, forcename): StructOrUnionOrEnum.force_the_name(self, forcename) if self.forcename is None: diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -26,6 +26,7 @@ #define _CFFI_OP_GLOBAL_VAR 33 #define _CFFI_OP_DLOPEN_FUNC 35 #define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 #define _CFFI_PRIM_VOID 0 #define _CFFI_PRIM_BOOL 1 @@ -78,7 +79,9 @@ #define _CFFI_PRIM_UINTMAX 47 #define _CFFI__NUM_PRIM 48 -#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) struct _cffi_global_s { diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -4,11 +4,6 @@ VERSION = "0x2601" -try: - int_type = (int, long) -except NameError: # Python 3 - int_type = int - class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): @@ -473,6 +468,10 @@ if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), tp.name.replace(' ', '_')) @@ -527,6 +526,8 @@ if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type(): return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double': return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: @@ -981,10 +982,6 @@ if not self.target_is_python and tp.is_integer_type(): type_op = CffiOp(OP_CONSTANT_INT, -1) else: - if not tp.sizeof_enabled(): - raise ffiplatform.VerificationError( - "constant '%s' is of type '%s', whose size is not known" - % (name, tp._get_c_name())) if self.target_is_python: const_kind = OP_DLOPEN_CONST else: @@ -1069,18 +1066,36 @@ self._do_collect_type(self._global_type(tp, name)) def _generate_cpy_variable_decl(self, tp, name): - pass + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,))) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() def _generate_cpy_variable_ctx(self, tp, name): tp = self._global_type(tp, name) type_index = self._typesdict[tp] - type_op = CffiOp(OP_GLOBAL_VAR, type_index) - if tp.sizeof_enabled(): - size = "sizeof(%s)" % (name,) + if self.target_is_python: + op = OP_GLOBAL_VAR else: - size = 0 + op = OP_GLOBAL_VAR_F self._lsts["global"].append( - GlobalExpr(name, '&%s' % name, type_op, size)) + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) # ---------- # emitting the opcodes for individual types @@ -1098,6 +1113,12 @@ ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -81,10 +81,16 @@ allsources.extend(kwds.pop('sources', [])) ext = Extension(name=module_name, sources=allsources, **kwds) - def make_mod(tmpdir): + def make_mod(tmpdir, pre_run=None): c_file = os.path.join(tmpdir, module_name + source_extension) log.info("generating cffi module %r" % c_file) mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) updated = recompiler.make_c_source(ffi, module_name, source, c_file) if not updated: log.info("already up-to-date") @@ -98,7 +104,8 @@ class build_ext_make_mod(base_class): def run(self): if ext.sources[0] == '$PLACEHOLDER': - ext.sources[0] = make_mod(self.build_temp) + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) base_class.run(self) dist.cmdclass['build_ext'] = build_ext_make_mod # NB. multiple runs here will create multiple 'build_ext_make_mod' diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -28,7 +28,7 @@ def _where_is_errno(): return standard_c_lib.__errno_location() -elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'): +elif sys.platform == 'darwin' or sys.platform.startswith('freebsd'): standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int) standard_c_lib.__error.argtypes = None def _where_is_errno(): diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -23,14 +23,14 @@ default_modules.update([ "_codecs", "gc", "_weakref", "marshal", "errno", "imp", "math", "cmath", "_sre", "_pickle_support", "operator", "parser", "symbol", "token", "_ast", - "_io", "_random", "__pypy__", "_testing" + "_io", "_random", "__pypy__", "_testing", "time" ]) # --allworkingmodules working_modules = default_modules.copy() working_modules.update([ - "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "time" , + "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -46,7 +46,11 @@ source. It'll acquire the GIL. Note: this is meant to be called *only once* or a few times at most. See - the `more complete example`_ below. + the `more complete example`_ below. In PyPy <= 2.6.0, the globals + dictionary is *reused* across multiple calls, giving potentially + strange results (e.g. objects dying too early). In PyPy >= 2.6.1, + you get a new globals dictionary for every call (but then, all globals + dictionaries are all kept alive forever, in ``sys._pypy_execute_source``). .. function:: int pypy_execute_source_ptr(char* source, void* ptr); diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -70,6 +70,20 @@ .. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv +Module xyz does not work in the sandboxed PyPy? +----------------------------------------------- + +You cannot import *any* extension module in a `sandboxed PyPy`_, +sorry. Even the built-in modules available are very limited. +Sandboxing in PyPy is a good proof of concept, really safe IMHO, but +it is only a proof of concept. It seriously requires someone working +on it. Before this occurs, it can only be used it for "pure Python" +examples: programs that import mostly nothing (or only pure Python +modules, recursively). + +.. _`sandboxed PyPy`: sandbox.html + + .. _`See below.`: Do CPython Extension modules work with PyPy? diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -31,15 +31,14 @@ and add the new file to pypy/doc/index-of-whatsnew.rst * go to pypy/tool/release and run ``force-builds.py `` - The following binaries should be built, however, we need more buildbots - - JIT: windows, linux, os/x, armhf, armel - - no JIT: windows, linux, os/x - - sandbox: linux, os/x + The following JIT binaries should be built, however, we need more buildbots + windows, linux-32, linux-64, osx64, armhf-raring, armhf-raspberrian, armel, + freebsd64 * wait for builds to complete, make sure there are no failures * download the builds, repackage binaries. Tag the release version and download and repackage source from bitbucket. You may find it - convenient to use the ``repackage.sh`` script in pypy/tools to do this. + convenient to use the ``repackage.sh`` script in pypy/tool/release to do this. Otherwise repackage and upload source "-src.tar.bz2" to bitbucket and to cobra, as some packagers prefer a clearly labeled source package diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-2.6.1.rst whatsnew-2.6.0.rst whatsnew-2.5.1.rst whatsnew-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 diff --git a/pypy/doc/sandbox.rst b/pypy/doc/sandbox.rst --- a/pypy/doc/sandbox.rst +++ b/pypy/doc/sandbox.rst @@ -103,12 +103,15 @@ Howto ----- -In pypy/goal:: +Grab a copy of the pypy repository_. In the directory pypy/goal, run:: ../../rpython/bin/rpython -O2 --sandbox targetpypystandalone.py If you don't have a regular PyPy installed, you should, because it's -faster to translate, but you can also run ``python translate.py`` instead. +faster to translate; but you can also run the same line with ``python`` +in front. + +.. _repository: https://bitbucket.org/pypy/pypy To run it, use the tools in the pypy/sandbox directory:: @@ -136,8 +139,6 @@ Not all operations are supported; e.g. if you type os.readlink('...'), the controller crashes with an exception and the subprocess is killed. Other operations make the subprocess die directly with a "Fatal RPython -error". None of this is a security hole; it just means that if you try -to run some random program, it risks getting killed depending on the -Python built-in functions it tries to call. This is a matter of the -sandboxing layer being incomplete so far, but it should not really be -a problem in practice. +error". None of this is a security hole. More importantly, *most other +built-in modules are not enabled. Please read all the warnings in this +page before complaining about this. Contributions welcome.* diff --git a/pypy/doc/whatsnew-2.6.1.rst b/pypy/doc/whatsnew-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-2.6.1.rst @@ -0,0 +1,76 @@ +======================== +What's new in PyPy 2.6.1 +======================== + +.. this is a revision shortly after release-2.6.0 +.. startrev: 91904d5c5188 + +.. branch: use_min_scalar +Correctly resolve the output dtype of ufunc(array, scalar) calls. + +.. branch: stdlib-2.7.10 + +Update stdlib to version 2.7.10 + +.. branch: issue2062 + +.. branch: disable-unroll-for-short-loops +The JIT no longer performs loop unrolling if the loop compiles to too much code. + +.. branch: run-create_cffi_imports + +Build cffi import libraries as part of translation by monkey-patching an +additional task into translation + +.. branch: int-float-list-strategy + +Use a compact strategy for Python lists that mix integers and floats, +at least if the integers fit inside 32 bits. These lists are now +stored as an array of floats, like lists that contain only floats; the +difference is that integers are stored as tagged NaNs. (This should +have no visible effect! After ``lst = [42, 42.5]``, the value of +``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) + +.. branch: cffi-callback-onerror +Part of cffi 1.2. + +.. branch: cffi-new-allocator +Part of cffi 1.2. + +.. branch: unicode-dtype + +Partial implementation of unicode dtype and unicode scalars. + +.. branch: dtypes-compatability + +Improve compatibility with numpy dtypes; handle offsets to create unions, +fix str() and repr(), allow specifying itemsize, metadata and titles, add flags, +allow subclassing dtype + +.. branch: indexing + +Refactor array indexing to support ellipses. + +.. branch: numpy-docstrings + +Allow the docstrings of built-in numpy objects to be set at run-time. + +.. branch: nditer-revisited + +Implement nditer 'buffered' flag and fix some edge cases + +.. branch: ufunc-reduce + +Allow multiple axes in ufunc.reduce() + +.. branch: fix-tinylang-goals + +Update tinylang goals to match current rpython + +.. branch: vmprof-review + +Clean up of vmprof, notably to handle correctly multiple threads + +.. branch: no_boehm_dl + +Remove extra link library from Boehm 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 @@ -2,23 +2,6 @@ What's new in PyPy 2.6+ ======================= -.. this is a revision shortly after release-2.6.0 -.. startrev: 91904d5c5188 +.. this is a revision shortly after release-2.6.1 +.. startrev: 07769be4057b -.. branch: use_min_scalar -Correctly resolve the output dtype of ufunc(array, scalar) calls. - -.. branch: stdlib-2.7.10 - -Update stdlib to version 2.7.10 - -.. branch: issue2062 - -.. branch: disable-unroll-for-short-loops -The JIT no longer performs loop unrolling if the loop compiles to too much code. - -.. branch: run-create_cffi_imports - -Build cffi import libraries as part of translation by monkey-patching an -aditional task into translation - diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -128,13 +128,7 @@ @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): - after = rffi.aroundstate.after - if after: after() - source = rffi.charp2str(ll_source) - res = _pypy_execute_source(source) - before = rffi.aroundstate.before - if before: before() - return rffi.cast(rffi.INT, res) + return pypy_execute_source_ptr(ll_source, 0) @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_execute_source_ptr') @@ -142,9 +136,7 @@ after = rffi.aroundstate.after if after: after() source = rffi.charp2str(ll_source) - space.setitem(w_globals, space.wrap('c_argument'), - space.wrap(ll_ptr)) - res = _pypy_execute_source(source) + res = _pypy_execute_source(source, ll_ptr) before = rffi.aroundstate.before if before: before() return rffi.cast(rffi.INT, res) @@ -169,15 +161,21 @@ before = rffi.aroundstate.before if before: before() - w_globals = space.newdict() - space.setitem(w_globals, space.wrap('__builtins__'), - space.builtin_modules['__builtin__']) - - def _pypy_execute_source(source): + def _pypy_execute_source(source, c_argument): try: - compiler = space.createcompiler() - stmt = compiler.compile(source, 'c callback', 'exec', 0) - stmt.exec_code(space, w_globals, w_globals) + w_globals = space.newdict(module=True) + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + space.setitem(w_globals, space.wrap('c_argument'), + space.wrap(c_argument)) + space.appexec([space.wrap(source), w_globals], """(src, glob): + import sys + stmt = compile(src, 'c callback', 'exec') + if not hasattr(sys, '_pypy_execute_source'): + sys._pypy_execute_source = [] + sys._pypy_execute_source.append(glob) + exec stmt in glob + """) except OperationError, e: debug("OperationError:") debug(" operror-type: " + e.w_type.getname(space)) @@ -297,7 +295,12 @@ options = make_dict(config) wrapstr = 'space.wrap(%r)' % (options) pypy.module.sys.Module.interpleveldefs['pypy_translation_info'] = wrapstr + if config.objspace.usemodules._cffi_backend: + self.hack_for_cffi_modules(driver) + return self.get_entry_point(config) + + def hack_for_cffi_modules(self, driver): # HACKHACKHACK # ugly hack to modify target goal from compile_c to build_cffi_imports # this should probably get cleaned up and merged with driver.create_exe @@ -336,8 +339,6 @@ driver.default_goal = 'build_cffi_imports' # HACKHACKHACK end - return self.get_entry_point(config) - def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy from pypy.module.pypyjit.hooks import pypy_hooks diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -11,7 +11,7 @@ INT_MIN, INT_MAX, UINT_MAX, USHRT_MAX from pypy.interpreter.executioncontext import (ExecutionContext, ActionFlag, - UserDelAction, CodeUniqueIds) + UserDelAction) from pypy.interpreter.error import OperationError, new_exception_class, oefmt from pypy.interpreter.argument import Arguments from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary @@ -200,7 +200,7 @@ w_result = space.get_and_call_function(w_impl, self) if space.isinstance_w(w_result, space.w_buffer): return w_result.buffer_w(space, flags) - raise TypeError + raise BufferInterfaceNotFound def readbuf_w(self, space): w_impl = space.lookup(self, '__buffer__') @@ -208,7 +208,7 @@ w_result = space.get_and_call_function(w_impl, self) if space.isinstance_w(w_result, space.w_buffer): return w_result.readbuf_w(space) - raise TypeError + raise BufferInterfaceNotFound def writebuf_w(self, space): w_impl = space.lookup(self, '__buffer__') @@ -216,7 +216,7 @@ w_result = space.get_and_call_function(w_impl, self) if space.isinstance_w(w_result, space.w_buffer): return w_result.writebuf_w(space) - raise TypeError + raise BufferInterfaceNotFound def charbuf_w(self, space): w_impl = space.lookup(self, '__buffer__') @@ -224,7 +224,7 @@ w_result = space.get_and_call_function(w_impl, self) if space.isinstance_w(w_result, space.w_buffer): return w_result.charbuf_w(space) - raise TypeError + raise BufferInterfaceNotFound def str_w(self, space): self._typed_unwrap_error(space, "string") @@ -354,6 +354,9 @@ class DescrMismatch(Exception): pass +class BufferInterfaceNotFound(Exception): + pass + def wrappable_class_name(Class): try: return Class.typedef.name @@ -388,7 +391,6 @@ self.actionflag = ActionFlag() # changed by the signal module self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) - self.code_unique_ids = CodeUniqueIds() self._code_of_sys_exc_info = None # can be overridden to a subclass @@ -667,16 +669,6 @@ assert ec is not None return ec - def register_code_callback(self, callback): - cui = self.code_unique_ids - cui.code_callback = callback - - def register_code_object(self, pycode): - cui = self.code_unique_ids - if cui.code_callback is None: - return - cui.code_callback(self, pycode) - def _freeze_(self): return True @@ -1403,7 +1395,7 @@ # New buffer interface, returns a buffer based on flags (PyObject_GetBuffer) try: return w_obj.buffer_w(self, flags) - except TypeError: + except BufferInterfaceNotFound: raise oefmt(self.w_TypeError, "'%T' does not have the buffer interface", w_obj) @@ -1411,7 +1403,7 @@ # Old buffer interface, returns a readonly buffer (PyObject_AsReadBuffer) try: return w_obj.readbuf_w(self) - except TypeError: + except BufferInterfaceNotFound: raise oefmt(self.w_TypeError, "expected a readable buffer object") @@ -1419,7 +1411,7 @@ # Old buffer interface, returns a writeable buffer (PyObject_AsWriteBuffer) try: return w_obj.writebuf_w(self) - except TypeError: + except BufferInterfaceNotFound: raise oefmt(self.w_TypeError, "expected a writeable buffer object") @@ -1427,7 +1419,7 @@ # Old buffer interface, returns a character buffer (PyObject_AsCharBuffer) try: return w_obj.charbuf_w(self) - except TypeError: + except BufferInterfaceNotFound: raise oefmt(self.w_TypeError, "expected a character buffer object") @@ -1451,11 +1443,11 @@ return self.str(w_obj).readbuf_w(self) try: return w_obj.buffer_w(self, 0) - except TypeError: + except BufferInterfaceNotFound: pass try: return w_obj.readbuf_w(self) - except TypeError: + except BufferInterfaceNotFound: self._getarg_error("string or buffer", w_obj) elif code == 's#': if self.isinstance_w(w_obj, self.w_str): @@ -1464,24 +1456,23 @@ return self.str(w_obj).str_w(self) try: return w_obj.readbuf_w(self).as_str() - except TypeError: + except BufferInterfaceNotFound: self._getarg_error("string or read-only buffer", w_obj) elif code == 'w*': try: - try: - return w_obj.buffer_w(self, self.BUF_WRITABLE) - except OperationError: - self._getarg_error("read-write buffer", w_obj) - except TypeError: + return w_obj.buffer_w(self, self.BUF_WRITABLE) + except OperationError: + self._getarg_error("read-write buffer", w_obj) + except BufferInterfaceNotFound: pass try: return w_obj.writebuf_w(self) - except TypeError: + except BufferInterfaceNotFound: self._getarg_error("read-write buffer", w_obj) elif code == 't#': try: return w_obj.charbuf_w(self) - except TypeError: + except BufferInterfaceNotFound: self._getarg_error("string or read-only character buffer", w_obj) else: assert False @@ -1503,13 +1494,13 @@ raise try: buf = w_obj.buffer_w(self, 0) - except TypeError: + except BufferInterfaceNotFound: pass else: return buf.as_str() try: buf = w_obj.readbuf_w(self) - except TypeError: + except BufferInterfaceNotFound: self._getarg_error("string or buffer", w_obj) else: return buf.as_str() diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -252,7 +252,8 @@ w_t, w_v, w_tb], """(where, objrepr, extra_line, t, v, tb): import sys, traceback - sys.stderr.write('From %s%s:\\n' % (where, objrepr)) + if where or objrepr: + sys.stderr.write('From %s%s:\\n' % (where, objrepr)) if extra_line: sys.stderr.write(extra_line) traceback.print_exception(t, v, tb) diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -590,11 +590,3 @@ # there is no list of length n: if n is large, then the GC # will run several times while walking the list, but it will # see lower and lower memory usage, with no lower bound of n. - -class CodeUniqueIds(object): - def __init__(self): - if sys.maxint == 2147483647: - self.code_unique_id = 0 # XXX this is wrong, it won't work on 32bit - else: - self.code_unique_id = 0x7000000000000000 - self.code_callback = None diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -15,7 +15,10 @@ self.running = False def descr__repr__(self, space): - code_name = self.pycode.co_name + if self.pycode is None: + code_name = '' + else: + code_name = self.pycode.co_name addrstring = self.getaddrstring(space) return space.wrap("" % (code_name, addrstring)) @@ -45,6 +48,8 @@ w_framestate, w_running = args_w if space.is_w(w_framestate, space.w_None): self.frame = None + self.space = space + self.pycode = None else: frame = instantiate(space.FrameClass) # XXX fish frame.descr__setstate__(space, w_framestate) @@ -62,9 +67,10 @@ def send_ex(self, w_arg, operr=None): pycode = self.pycode - if jit.we_are_jitted() and should_not_inline(pycode): - generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg, - operr=operr, pycode=pycode) + if pycode is not None: + if jit.we_are_jitted() and should_not_inline(pycode): + generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg, + operr=operr, pycode=pycode) return self._send_ex(w_arg, operr) def _send_ex(self, w_arg, operr): @@ -158,7 +164,10 @@ return self.pycode def descr__name__(self, space): - code_name = self.pycode.co_name + if self.pycode is None: + code_name = '' + else: + code_name = self.pycode.co_name return space.wrap(code_name) # Results can be either an RPython list of W_Root, or it can be an diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -85,7 +85,7 @@ self.magic = magic self._signature = cpython_code_signature(self) self._initialize() - space.register_code_object(self) + self._init_ready() def _initialize(self): if self.co_cellvars: @@ -127,14 +127,8 @@ from pypy.objspace.std.mapdict import init_mapdict_cache init_mapdict_cache(self) - cui = self.space.code_unique_ids - self._unique_id = cui.code_unique_id - cui.code_unique_id += 4 # so we have two bits that we can mark stuff - # with - - def _get_full_name(self): - return "py:%s:%d:%s" % (self.co_name, self.co_firstlineno, - self.co_filename) + def _init_ready(self): + "This is a hook for the vmprof module, which overrides this method." def _cleanup_(self): if (self.magic == cpython_magic and diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -711,11 +711,17 @@ w_item = self.popvalue() if self.space.is_w(w_stream, self.space.w_None): w_stream = sys_stdout(self.space) # grumble grumble special cases - print_item_to(self.space, w_item, w_stream) + print_item_to(self.space, self._printable_object(w_item), w_stream) def PRINT_ITEM(self, oparg, next_instr): w_item = self.popvalue() - print_item(self.space, w_item) + print_item(self.space, self._printable_object(w_item)) + + def _printable_object(self, w_obj): + space = self.space + if not space.isinstance_w(w_obj, space.w_unicode): + w_obj = space.str(w_obj) + return w_obj def PRINT_NEWLINE_TO(self, oparg, next_instr): w_stream = self.popvalue() @@ -1535,9 +1541,9 @@ stream.write(" ") # give to write() an argument which is either a string or a unicode - # (and let it deals itself with unicode handling) - if not isinstance(x, unicode): - x = str(x) + # (and let it deals itself with unicode handling). The check "is + # unicode" should not use isinstance() at app-level, because that + # could be fooled by strange objects, so it is done at interp-level. stream.write(x) # add a softspace unless we just printed a string which ends in a '\t' diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py --- a/pypy/interpreter/test/test_interpreter.py +++ b/pypy/interpreter/test/test_interpreter.py @@ -299,6 +299,30 @@ finally: sys.stdout = save + def test_print_strange_object(self): + import sys + + class A(object): + def __getattribute__(self, name): + print "seeing", name + def __str__(self): + return 'A!!' + save = sys.stdout + class Out(object): + def __init__(self): + self.data = [] + def write(self, x): + self.data.append((type(x), x)) + sys.stdout = out = Out() + try: + a = A() + assert out.data == [] + print a + assert out.data == [(str, 'A!!'), + (str, '\n')] + finally: + sys.stdout = save + def test_identity(self): def f(x): return x assert f(666) == 666 diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -491,6 +491,22 @@ assert pack.mod is result + def test_pickle_generator_crash(self): + import pickle + + def f(): + yield 0 + + x = f() + x.next() + try: + x.next() + except StopIteration: + y = pickle.loads(pickle.dumps(x)) + assert 'finished' in y.__name__ + assert 'finished' in repr(y) + assert y.gi_code is None + class AppTestGeneratorCloning: def setup_class(cls): diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -53,6 +53,33 @@ last = last + x return last + +class _Cons(object): + def __init__(self, prev, iter): + self.prev = prev + self.iter = iter + + def fetch(self): + # recursive, loop-less version of the algorithm: works best for a + # fixed number of "collections" in the call to map(func, *collections) + prev = self.prev + if prev is None: + args1 = () + stop = True + else: + args1, stop = prev.fetch() + iter = self.iter + if iter is None: + val = None + else: + try: + val = next(iter) + stop = False + except StopIteration: + self.iter = None + val = None + return args1 + (val,), stop + def map(func, *collections): """map(function, sequence[, sequence, ...]) -> list @@ -69,45 +96,30 @@ if num_collections == 1: if none_func: return list(collections[0]) - # Special case for the really common case of a single collection, - # this can be eliminated if we could unroll that loop that creates - # `args` based on whether or not len(collections) was constant + # Special case for the really common case of a single collection seq = collections[0] with _ManagedNewlistHint(operator._length_hint(seq, 0)) as result: for item in seq: result.append(func(item)) return result - # Gather the iterators (pair of (iter, has_finished)) and guess the + # Gather the iterators into _Cons objects and guess the # result length (the max of the input lengths) - iterators = [] + c = None max_hint = 0 for seq in collections: - iterators.append((iter(seq), False)) + c = _Cons(c, iter(seq)) max_hint = max(max_hint, operator._length_hint(seq, 0)) with _ManagedNewlistHint(max_hint) as result: while True: - cont = False - args = [] - for idx, (iterator, has_finished) in enumerate(iterators): - val = None - if not has_finished: - try: - val = next(iterator) - except StopIteration: - iterators[idx] = (None, True) - else: - cont = True - args.append(val) - args = tuple(args) - if cont: - if none_func: - result.append(args) - else: - result.append(func(*args)) + args, stop = c.fetch() + if stop: + return result + if none_func: + result.append(args) else: - return result + result.append(func(*args)) class _ManagedNewlistHint(object): """ Context manager returning a newlist_hint upon entry. diff --git a/pypy/module/__builtin__/test/test_abstractinst.py b/pypy/module/__builtin__/test/test_abstractinst.py --- a/pypy/module/__builtin__/test/test_abstractinst.py +++ b/pypy/module/__builtin__/test/test_abstractinst.py @@ -202,3 +202,17 @@ __subclass__ = set([int]) assert issubclass(int, Integer) assert issubclass(int, (Integer,)) + + def test_dont_call_instancecheck_fast_path(self): + called = [] + + class M(type): + def __instancecheck__(self, obj): + called.append("called") + + class C: + __metaclass__ = M + + c = C() + assert isinstance(c, C) + assert not called diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py --- a/pypy/module/__builtin__/test/test_functional.py +++ b/pypy/module/__builtin__/test/test_functional.py @@ -57,6 +57,11 @@ b = [] assert map(lambda x, y: x, a, b) == a + def test_map_second_item(self): + a = [] + b = [1, 2, 3, 4, 5] + assert map(lambda x, y: y, a, b) == b + def test_map_iterables(self): class A(object): def __init__(self, n): diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -62,6 +62,7 @@ } interpleveldefs = { + 'attach_gdb' : 'interp_magic.attach_gdb', 'internal_repr' : 'interp_magic.internal_repr', 'bytebuffer' : 'bytebuffer.bytebuffer', 'identity_dict' : 'interp_identitydict.W_IdentityDict', @@ -100,8 +101,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" - if not self.space.config.translating: - self.extra_interpdef('interp_pdb', 'interp_magic.interp_pdb') if self.space.config.objspace.std.withmethodcachecounter: self.extra_interpdef('method_cache_counter', 'interp_magic.method_cache_counter') diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -15,12 +15,10 @@ return space.wrap('%r' % (w_object,)) -def interp_pdb(space): - """Run an interp-level pdb. - This is not available in translated versions of PyPy.""" - assert not we_are_translated() - import pdb - pdb.set_trace() +def attach_gdb(space): + """Run an interp-level gdb (or pdb when untranslated)""" + from rpython.rlib.debug import attach_gdb + attach_gdb() @unwrap_spec(name=str) diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.1.2" +VERSION = "1.3.0" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/allocator.py b/pypy/module/_cffi_backend/allocator.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/allocator.py @@ -0,0 +1,86 @@ +from pypy.interpreter.error import oefmt +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault + +from rpython.rtyper.lltypesystem import lltype, rffi + + +class W_Allocator(W_Root): + _immutable_ = True + + def __init__(self, ffi, w_alloc, w_free, should_clear_after_alloc): + self.ffi = ffi # may be None + self.w_alloc = w_alloc + self.w_free = w_free + self.should_clear_after_alloc = should_clear_after_alloc + + def allocate(self, space, datasize, ctype, length=-1): + from pypy.module._cffi_backend import cdataobj, ctypeptr + if self.w_alloc is None: + if self.should_clear_after_alloc: + ptr = lltype.malloc(rffi.CCHARP.TO, datasize, + flavor='raw', zero=True) + else: + ptr = lltype.malloc(rffi.CCHARP.TO, datasize, + flavor='raw', zero=False) + return cdataobj.W_CDataNewStd(space, ptr, ctype, length) + else: + w_raw_cdata = space.call_function(self.w_alloc, + space.wrap(datasize)) + if not isinstance(w_raw_cdata, cdataobj.W_CData): + raise oefmt(space.w_TypeError, + "alloc() must return a cdata object (got %T)", + w_raw_cdata) + if not isinstance(w_raw_cdata.ctype, ctypeptr.W_CTypePtrOrArray): + raise oefmt(space.w_TypeError, + "alloc() must return a cdata pointer, not '%s'", + w_raw_cdata.ctype.name) + # + ptr = w_raw_cdata.unsafe_escaping_ptr() + if not ptr: + raise oefmt(space.w_MemoryError, "alloc() returned NULL") + # + if self.should_clear_after_alloc: + rffi.c_memset(rffi.cast(rffi.VOIDP, ptr), 0, + rffi.cast(rffi.SIZE_T, datasize)) + # + if self.w_free is None: + # use this class which does not have a __del__, but still + # keeps alive w_raw_cdata + res = cdataobj.W_CDataNewNonStdNoFree(space, ptr, ctype, length) + else: + res = cdataobj.W_CDataNewNonStdFree(space, ptr, ctype, length) + res.w_free = self.w_free + res.w_raw_cdata = w_raw_cdata + return res + + @unwrap_spec(w_init=WrappedDefault(None)) + def descr_call(self, space, w_arg, w_init): + ffi = self.ffi + assert ffi is not None + w_ctype = ffi.ffi_type(w_arg, ffi.ACCEPT_STRING | ffi.ACCEPT_CTYPE) + return w_ctype.newp(w_init, self) + + +W_Allocator.typedef = TypeDef( + 'FFIAllocator', + __call__ = interp2app(W_Allocator.descr_call), + ) +W_Allocator.typedef.acceptable_as_base_class = False + + +def new_allocator(ffi, w_alloc, w_free, should_clear_after_alloc): + space = ffi.space + if space.is_none(w_alloc): + w_alloc = None + if space.is_none(w_free): + w_free = None + if w_alloc is None and w_free is not None: + raise oefmt(space.w_TypeError, "cannot pass 'free' without 'alloc'") + alloc = W_Allocator(ffi, w_alloc, w_free, bool(should_clear_after_alloc)) + return space.wrap(alloc) + + +default_allocator = W_Allocator(None, None, None, should_clear_after_alloc=True) +nonzero_allocator = W_Allocator(None, None, None,should_clear_after_alloc=False) diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -22,8 +22,9 @@ class W_CDataCallback(W_CData): #_immutable_fields_ = ... ll_error = lltype.nullptr(rffi.CCHARP.TO) + w_onerror = None - def __init__(self, space, ctype, w_callable, w_error): + def __init__(self, space, ctype, w_callable, w_error, w_onerror): raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc()) W_CData.__init__(self, space, raw_closure, ctype) # @@ -31,6 +32,12 @@ raise oefmt(space.w_TypeError, "expected a callable object, not %T", w_callable) self.w_callable = w_callable + if not space.is_none(w_onerror): + if not space.is_true(space.callable(w_onerror)): + raise oefmt(space.w_TypeError, + "expected a callable object for 'onerror', not %T", + w_onerror) + self.w_onerror = w_onerror # fresult = self.getfunctype().ctitem size = fresult.size @@ -161,6 +168,29 @@ STDERR = 2 + at jit.dont_look_inside +def _handle_applevel_exception(space, callback, e, ll_res, extra_line): + callback.write_error_return_value(ll_res) + if callback.w_onerror is None: + callback.print_error(e, extra_line) + else: + try: + e.normalize_exception(space) + w_t = e.w_type + w_v = e.get_w_value(space) + w_tb = space.wrap(e.get_traceback()) + w_res = space.call_function(callback.w_onerror, + w_t, w_v, w_tb) + if not space.is_none(w_res): + callback.convert_result(ll_res, w_res) + except OperationError, e2: + # double exception! print a double-traceback... + callback.print_error(e, extra_line) # original traceback + e2.write_unraisable(space, '', with_traceback=True, + extra_line="\nDuring the call to 'onerror', " + "another exception occurred:\n\n") + + @jit.jit_callback("CFFI") def _invoke_callback(ffi_cif, ll_res, ll_args, ll_userdata): """ Callback specification. @@ -178,7 +208,7 @@ try: os.write(STDERR, "SystemError: invoking a callback " "that was already freed\n") - except OSError: + except: pass # In this case, we don't even know how big ll_res is. Let's assume # it is just a 'ffi_arg', and store 0 there. @@ -195,9 +225,7 @@ extra_line = "Trying to convert the result back to C:\n" callback.convert_result(ll_res, w_res) except OperationError, e: - # got an app-level exception - callback.print_error(e, extra_line) - callback.write_error_return_value(ll_res) + _handle_applevel_exception(space, callback, e, ll_res, extra_line) # except Exception, e: # oups! last-level attempt to recover. @@ -205,7 +233,7 @@ os.write(STDERR, "SystemError: callback raised ") os.write(STDERR, str(e)) os.write(STDERR, "\n") - except OSError: + except: pass callback.write_error_return_value(ll_res) if must_leave: diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -363,16 +363,19 @@ def _sizeof(self): return self.ctype.size + def with_gc(self, w_destructor): + with self as ptr: + return W_CDataGCP(self.space, ptr, self.ctype, self, w_destructor) + class W_CDataMem(W_CData): - """This is the base class used for cdata objects that own and free - their memory. Used directly by the results of cffi.cast('int', x) - or other primitive explicitly-casted types. It is further subclassed - by W_CDataNewOwning.""" + """This is used only by the results of cffi.cast('int', x) + or other primitive explicitly-casted types.""" _attrs_ = [] - def __init__(self, space, size, ctype): - cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', zero=True) + def __init__(self, space, ctype): + cdata = lltype.malloc(rffi.CCHARP.TO, ctype.size, flavor='raw', + zero=False) W_CData.__init__(self, space, cdata, ctype) @rgc.must_be_light_finalizer @@ -380,36 +383,65 @@ lltype.free(self._ptr, flavor='raw') -class W_CDataNewOwning(W_CDataMem): - """This is the class used for the cata objects created by newp().""" - _attrs_ = [] +class W_CDataNewOwning(W_CData): + """This is the abstract base class used for cdata objects created + by newp(). They create and free their own memory according to an + allocator.""" + + # the 'length' is either >= 0 for arrays, or -1 for pointers. + _attrs_ = ['length'] + _immutable_fields_ = ['length'] + + def __init__(self, space, cdata, ctype, length=-1): + W_CData.__init__(self, space, cdata, ctype) + self.length = length def _repr_extra(self): return self._repr_extra_owning() - -class W_CDataNewOwningLength(W_CDataNewOwning): - """Subclass with an explicit length, for allocated instances of - the C type 'foo[]'.""" - _attrs_ = ['length'] - _immutable_fields_ = ['length'] - - def __init__(self, space, size, ctype, length): - W_CDataNewOwning.__init__(self, space, size, ctype) - self.length = length - def _sizeof(self): - from pypy.module._cffi_backend import ctypearray ctype = self.ctype - assert isinstance(ctype, ctypearray.W_CTypeArray) - return self.length * ctype.ctitem.size + if self.length >= 0: + from pypy.module._cffi_backend import ctypearray + assert isinstance(ctype, ctypearray.W_CTypeArray) + return self.length * ctype.ctitem.size + else: + return ctype.size def get_array_length(self): return self.length +class W_CDataNewStd(W_CDataNewOwning): + """Subclass using the standard allocator, lltype.malloc()/lltype.free()""" + _attrs_ = [] + + @rgc.must_be_light_finalizer + def __del__(self): + lltype.free(self._ptr, flavor='raw') + + +class W_CDataNewNonStdNoFree(W_CDataNewOwning): + """Subclass using a non-standard allocator, no free()""" + _attrs_ = ['w_raw_cdata'] + +class W_CDataNewNonStdFree(W_CDataNewNonStdNoFree): + """Subclass using a non-standard allocator, with a free()""" + _attrs_ = ['w_free'] + + def __del__(self): + self.clear_all_weakrefs() + self.enqueue_for_destruction(self.space, + W_CDataNewNonStdFree.call_destructor, + 'destructor of ') + + def call_destructor(self): + assert isinstance(self, W_CDataNewNonStdFree) From noreply at buildbot.pypy.org Tue Sep 1 11:08:49 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 11:08:49 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: fix translation Message-ID: <20150901090849.B15E01C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79342:836e3fb3e837 Date: 2015-09-01 10:02 +0100 http://bitbucket.org/pypy/pypy/changeset/836e3fb3e837/ Log: fix translation diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -798,12 +798,14 @@ for k in d: yield (k, _expected_hash(d, k)) + at specialize.call_location() def iterkeys_with_hash(d): """Iterates (key, hash) pairs without recomputing the hash.""" if not we_are_translated(): return _iterkeys_with_hash_untranslated(d) return d.iterkeys_with_hash() + at specialize.call_location() def contains_with_hash(d, key, h): """Same as 'key in d'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" @@ -812,6 +814,7 @@ return key in d return d.contains_with_hash(key, h) + at specialize.call_location() def setitem_with_hash(d, key, h, value): """Same as 'd[key] = value'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" @@ -821,6 +824,7 @@ return d.setitem_with_hash(key, h, value) + at specialize.call_location() def getitem_with_hash(d, key, h): """Same as 'd[key]'. The extra argument is the hash. Use this only if you got the hash just now from some other ..._with_hash() function.""" From noreply at buildbot.pypy.org Tue Sep 1 11:41:16 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 11:41:16 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: delitem_with_hash Message-ID: <20150901094116.EE87F1C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79343:f09d931056ab Date: 2015-09-01 11:33 +0200 http://bitbucket.org/pypy/pypy/changeset/f09d931056ab/ Log: delitem_with_hash diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -479,6 +479,10 @@ return pair(self, s_key).getitem() method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -833,6 +833,16 @@ return d[key] return d.getitem_with_hash(key, h) + at specialize.call_location() +def delitem_with_hash(d, key, h): + """Same as 'del d[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + del d[key] + return + d.delitem_with_hash(key, h) + # ____________________________________________________________ def import_from_mixin(M, special_methods=['__init__', '__del__']): diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -636,6 +636,21 @@ res = interpret(f, [27]) assert res == 42 +def test_delitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + try: + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + except KeyError: + pass + else: + raise AssertionError + return 0 + + f(29) + interpret(f, [27]) + def test_rdict_with_hash(): def f(i): d = r_dict(strange_key_eq, strange_key_hash) diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -389,6 +389,14 @@ v_dict, v_key, v_hash) return self.recast_value(hop.llops, v_res) + def rtype_method_delitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -404,7 +412,7 @@ if not r_dict.custom_eq_hash: hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) + hop.gendirectcall(ll_dict_delitem, v_dict, v_key) def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr) @@ -778,6 +786,12 @@ raise KeyError _ll_dict_del(d, index) +def ll_dict_delitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_DELETE) + if index < 0: + raise KeyError + _ll_dict_del(d, index) + @jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i)) def _ll_dict_del(d, index): d.entries.mark_deleted(index) From noreply at buildbot.pypy.org Tue Sep 1 11:41:19 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 11:41:19 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Add the _with_hash() methods more systematically Message-ID: <20150901094119.195B91C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79344:70d822f6440b Date: 2015-09-01 11:41 +0200 http://bitbucket.org/pypy/pypy/changeset/70d822f6440b/ Log: Add the _with_hash() methods more systematically diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -9,7 +9,7 @@ from rpython.rlib.objectmodel import r_dict from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash -from rpython.rlib.objectmodel import setitem_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -991,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1022,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1107,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1127,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1154,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True From noreply at buildbot.pypy.org Tue Sep 1 12:11:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 12:11:23 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: iteritems_with_hash() Message-ID: <20150901101123.4038A1C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79345:9d075ff7b6f1 Date: 2015-09-01 11:56 +0200 http://bitbucket.org/pypy/pypy/changeset/9d075ff7b6f1/ Log: iteritems_with_hash() diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -403,18 +403,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - if variant == 'keys_with_hash': - return SomeTuple((self.dictdef.read_key(), s_Int)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -455,6 +459,9 @@ def method_iterkeys_with_hash(self): return SomeIterator(self, 'keys_with_hash') + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -805,6 +805,17 @@ return _iterkeys_with_hash_untranslated(d) return d.iterkeys_with_hash() +def _iteritems_with_hash_untranslated(d): + for k, v in d.iteritems(): + yield (k, v, _expected_hash(d, k)) + + at specialize.call_location() +def iteritems_with_hash(d): + """Iterates (key, value, keyhash) triples without recomputing the hash.""" + if not we_are_translated(): + return _iteritems_with_hash_untranslated(d) + return d.iteritems_with_hash() + @specialize.call_location() def contains_with_hash(d, key, h): """Same as 'key in d'. The extra argument is the hash. Use this only diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -606,6 +606,20 @@ r = interpret(f, [29]) assert r == 0.0 +def test_iteritems_with_hash(): + def f(i): + d = {i+.0: 5, i+.5: 6} + total = 0 + for k, v, h in iteritems_with_hash(d): + total += k * h * v + total -= (i + 0.0) * compute_hash(i + 0.0) * 5 + total -= (i + 0.5) * compute_hash(i + 0.5) * 6 + return total + + assert f(29) == 0.0 + r = interpret(f, [29]) + assert r == 0.0 + def test_contains_with_hash(): def f(i): d = {i+.5: 5} diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -339,6 +339,10 @@ hop.exception_cannot_occur() return DictIteratorRepr(self, "keys_with_hash").newiter(hop) + def rtype_method_iteritems_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "items_with_hash").newiter(hop) + def rtype_method_clear(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py --- a/rpython/rtyper/rdict.py +++ b/rpython/rtyper/rdict.py @@ -80,7 +80,7 @@ hop.exception_is_here() v_index = hop.gendirectcall(self._ll_dictnext, v_iter) if ((variant == 'items' and hop.r_result.lowleveltype != lltype.Void) or - variant == 'keys_with_hash'): + variant == 'keys_with_hash' or variant == 'items_with_hash'): # this allocates the tuple for the result, directly in the function # where it will be used (likely). This will let it be removed. c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) @@ -99,22 +99,32 @@ c_key = hop.inputconst(lltype.Void, 'key') v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], resulttype=KEY) - if variant == 'values' or variant == 'items': + if (variant == 'values' or variant == 'items' + or variant == 'items_with_hash'): VALUE = ENTRIES.TO.OF.value c_value = hop.inputconst(lltype.Void, 'value') v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], resulttype=VALUE) - elif variant == 'keys_with_hash': - v_value = hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) + if variant == 'keys_with_hash' or variant == 'items_with_hash': + v_hash = hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) # if variant == 'keys' or variant == 'reversed': return self.r_dict.recast_key(hop.llops, v_key) elif variant == 'values': return self.r_dict.recast_value(hop.llops, v_value) + elif variant == 'keys_with_hash': + ITEM0 = v_result.concretetype.TO.item0 + if ITEM0 != v_key.concretetype: + v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0) + c_item0 = hop.inputconst(lltype.Void, 'item0') + c_item1 = hop.inputconst(lltype.Void, 'item1') + hop.genop('setfield', [v_result, c_item0, v_key]) + hop.genop('setfield', [v_result, c_item1, v_hash]) + return v_result elif hop.r_result.lowleveltype == lltype.Void: return hop.inputconst(lltype.Void, None) else: - assert variant == 'items' or variant == 'keys_with_hash' + assert variant == 'items' or variant == 'items_with_hash' ITEM0 = v_result.concretetype.TO.item0 ITEM1 = v_result.concretetype.TO.item1 if ITEM0 != v_key.concretetype: @@ -125,4 +135,7 @@ c_item1 = hop.inputconst(lltype.Void, 'item1') hop.genop('setfield', [v_result, c_item0, v_key]) hop.genop('setfield', [v_result, c_item1, v_value]) + if variant == 'items_with_hash': + c_item2 = hop.inputconst(lltype.Void, 'item2') + hop.genop('setfield', [v_result, c_item2, v_hash]) return v_result From noreply at buildbot.pypy.org Tue Sep 1 12:11:25 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 12:11:25 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Use iteritems_with_hash() in dictmultiobject in order to let d1.update(d2) Message-ID: <20150901101125.8AB8D1C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79346:f45fa5542e6b Date: 2015-09-01 12:11 +0200 http://bitbucket.org/pypy/pypy/changeset/f45fa5542e6b/ Log: Use iteritems_with_hash() in dictmultiobject in order to let d1.update(d2) not recompute hashes diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) From noreply at buildbot.pypy.org Tue Sep 1 13:15:51 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 13:15:51 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Avoid duplicating code Message-ID: <20150901111551.51CCE1C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79347:d5a4b8506d27 Date: 2015-09-01 13:15 +0200 http://bitbucket.org/pypy/pypy/changeset/d5a4b8506d27/ Log: Avoid duplicating code diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -584,11 +584,7 @@ return bool(d) and d.num_live_items != 0 def ll_dict_getitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) - if index >= 0: - return d.entries[index].value - else: - raise KeyError + return ll_dict_getitem_with_hash(d, key, d.keyhash(key)) def ll_dict_getitem_with_hash(d, key, hash): index = d.lookup_function(d, key, hash, FLAG_LOOKUP) @@ -598,13 +594,11 @@ raise KeyError def ll_dict_setitem(d, key, value): - hash = d.keyhash(key) - index = d.lookup_function(d, key, hash, FLAG_STORE) - return _ll_dict_setitem_lookup_done(d, key, value, hash, index) + ll_dict_setitem_with_hash(d, key, d.keyhash(key), value) def ll_dict_setitem_with_hash(d, key, hash, value): index = d.lookup_function(d, key, hash, FLAG_STORE) - return _ll_dict_setitem_lookup_done(d, key, value, hash, index) + _ll_dict_setitem_lookup_done(d, key, value, hash, index) # It may be safe to look inside always, it has a few branches though, and their # frequencies needs to be investigated. @@ -785,10 +779,7 @@ def ll_dict_delitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_DELETE) - if index < 0: - raise KeyError - _ll_dict_del(d, index) + ll_dict_delitem_with_hash(d, key, d.keyhash(key)) def ll_dict_delitem_with_hash(d, key, hash): index = d.lookup_function(d, key, hash, FLAG_DELETE) @@ -1274,8 +1265,7 @@ ll_dict_items = _make_ll_keys_values_items('items') def ll_dict_contains(d, key): - i = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) - return i >= 0 + return ll_dict_contains_with_hash(d, key, d.keyhash(key)) def ll_dict_contains_with_hash(d, key, hash): i = d.lookup_function(d, key, hash, FLAG_LOOKUP) From noreply at buildbot.pypy.org Tue Sep 1 13:15:53 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 13:15:53 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Split this huge function into 6 subfunctions Message-ID: <20150901111553.810FA1C050D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79348:11a2870d60ff Date: 2015-09-01 13:15 +0200 http://bitbucket.org/pypy/pypy/changeset/11a2870d60ff/ Log: Split this huge function into 6 subfunctions diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py --- a/rpython/rtyper/rdict.py +++ b/rpython/rtyper/rdict.py @@ -72,21 +72,14 @@ return hop.gendirectcall(self.ll_dictiter, citerptr, v_dict) def rtype_next(self, hop): - variant = self.variant v_iter, = hop.inputargs(self) # record that we know about these two possible exceptions hop.has_implicit_exception(StopIteration) hop.has_implicit_exception(RuntimeError) hop.exception_is_here() v_index = hop.gendirectcall(self._ll_dictnext, v_iter) - if ((variant == 'items' and hop.r_result.lowleveltype != lltype.Void) or - variant == 'keys_with_hash' or variant == 'items_with_hash'): - # this allocates the tuple for the result, directly in the function - # where it will be used (likely). This will let it be removed. - c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) - cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) - v_result = hop.genop('malloc', [c1, cflags], - resulttype = hop.r_result.lowleveltype) + # + # read 'iter.dict.entries' DICT = self.lowleveltype.TO.dict c_dict = hop.inputconst(lltype.Void, 'dict') v_dict = hop.genop('getfield', [v_iter, c_dict], resulttype=DICT) @@ -94,48 +87,61 @@ c_entries = hop.inputconst(lltype.Void, 'entries') v_entries = hop.genop('getfield', [v_dict, c_entries], resulttype=ENTRIES) - if variant != 'values': - KEY = ENTRIES.TO.OF.key - c_key = hop.inputconst(lltype.Void, 'key') - v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], - resulttype=KEY) - if (variant == 'values' or variant == 'items' - or variant == 'items_with_hash'): - VALUE = ENTRIES.TO.OF.value - c_value = hop.inputconst(lltype.Void, 'value') - v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], - resulttype=VALUE) - if variant == 'keys_with_hash' or variant == 'items_with_hash': - v_hash = hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) - # - if variant == 'keys' or variant == 'reversed': - return self.r_dict.recast_key(hop.llops, v_key) - elif variant == 'values': - return self.r_dict.recast_value(hop.llops, v_value) - elif variant == 'keys_with_hash': - ITEM0 = v_result.concretetype.TO.item0 - if ITEM0 != v_key.concretetype: - v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0) - c_item0 = hop.inputconst(lltype.Void, 'item0') - c_item1 = hop.inputconst(lltype.Void, 'item1') - hop.genop('setfield', [v_result, c_item0, v_key]) - hop.genop('setfield', [v_result, c_item1, v_hash]) - return v_result - elif hop.r_result.lowleveltype == lltype.Void: + # call the correct variant_*() method + method = getattr(self, 'variant_' + self.variant) + return method(hop, ENTRIES, v_entries, v_index) + + def get_tuple_result(self, hop, items_v): + # this allocates the tuple for the result, directly in the function + # where it will be used (likely). This will let it be removed. + if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) - else: - assert variant == 'items' or variant == 'items_with_hash' - ITEM0 = v_result.concretetype.TO.item0 - ITEM1 = v_result.concretetype.TO.item1 - if ITEM0 != v_key.concretetype: - v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0) - if ITEM1 != v_value.concretetype: - v_value = hop.genop('cast_pointer', [v_value], resulttype=ITEM1) - c_item0 = hop.inputconst(lltype.Void, 'item0') - c_item1 = hop.inputconst(lltype.Void, 'item1') - hop.genop('setfield', [v_result, c_item0, v_key]) - hop.genop('setfield', [v_result, c_item1, v_value]) - if variant == 'items_with_hash': - c_item2 = hop.inputconst(lltype.Void, 'item2') - hop.genop('setfield', [v_result, c_item2, v_hash]) - return v_result + c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) + cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) + v_result = hop.genop('malloc', [c1, cflags], + resulttype = hop.r_result.lowleveltype) + for i, v_item in enumerate(items_v): + ITEM = getattr(v_result.concretetype.TO, 'item%d' % i) + if ITEM != v_item.concretetype: + assert isinstance(ITEM, lltype.Ptr) + v_item = hop.genop('cast_pointer', [v_item], resulttype=ITEM) + c_item = hop.inputconst(lltype.Void, 'item%d' % i) + hop.genop('setfield', [v_result, c_item, v_item]) + return v_result + + def variant_keys(self, hop, ENTRIES, v_entries, v_index): + KEY = ENTRIES.TO.OF.key + c_key = hop.inputconst(lltype.Void, 'key') + v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], + resulttype=KEY) + return self.r_dict.recast_key(hop.llops, v_key) + + variant_reversed = variant_keys + + def variant_values(self, hop, ENTRIES, v_entries, v_index): + VALUE = ENTRIES.TO.OF.value + c_value = hop.inputconst(lltype.Void, 'value') + v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], + resulttype=VALUE) + return self.r_dict.recast_value(hop.llops, v_value) + + def variant_items(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value)) + + def variant_hashes(self, hop, ENTRIES, v_entries, v_index): + # there is not really a variant 'hashes', but this method is + # convenient for the following variants + return hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) + + def variant_keys_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_hash)) + + def variant_items_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value, v_hash)) From noreply at buildbot.pypy.org Tue Sep 1 16:46:51 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 16:46:51 +0200 (CEST) Subject: [pypy-commit] pypy default: This code moved Message-ID: <20150901144651.9BB541C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79351:341fb1900036 Date: 2015-09-01 15:04 +0200 http://bitbucket.org/pypy/pypy/changeset/341fb1900036/ Log: This code moved diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -430,7 +430,7 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at From noreply at buildbot.pypy.org Tue Sep 1 16:55:35 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 16:55:35 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Re-enable colors and display of text for variables. Change the Message-ID: <20150901145535.9593C1C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79352:cfe3990e4803 Date: 2015-09-01 16:22 +0200 http://bitbucket.org/pypy/pypy/changeset/cfe3990e4803/ Log: Re-enable colors and display of text for variables. Change the bridge's variable names to match the parent loop's variable names. diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -775,6 +775,7 @@ new_loop.original_jitcell_token = metainterp.resumekey_original_loop_token inputargs = new_loop.inputargs if not we_are_translated(): + self._debug_subinputargs = new_loop.inputargs self._debug_suboperations = new_loop.operations propagate_original_jitcell_token(new_loop) send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata, diff --git a/rpython/jit/metainterp/graphpage.py b/rpython/jit/metainterp/graphpage.py --- a/rpython/jit/metainterp/graphpage.py +++ b/rpython/jit/metainterp/graphpage.py @@ -4,11 +4,21 @@ from rpython.jit.metainterp.resoperation import rop class SubGraph: - def __init__(self, suboperations): - self.suboperations = suboperations + def __init__(self, op): + self.failargs = op.getfailargs() + self.subinputargs = op.getdescr()._debug_subinputargs + self.suboperations = op.getdescr()._debug_suboperations def get_operations(self): return self.suboperations - def get_display_text(self): + def get_display_text(self, memo): + # copy the display of variables in this subgraph (a bridge) + # so that they match variables in the parent graph across the + # guard failure + for failarg, inputarg in zip(self.failargs, self.subinputargs): + try: + memo[inputarg] = memo[failarg] + except KeyError: + pass return None def display_procedures(procedures, errmsg=None, highlight_procedures={}, metainterp_sd=None): @@ -17,8 +27,7 @@ for graph, highlight in graphs: for op in graph.get_operations(): if is_interesting_guard(op): - graphs.append((SubGraph(op.getdescr()._debug_suboperations), - highlight)) + graphs.append((SubGraph(op), highlight)) graphpage = ResOpGraphPage(graphs, errmsg, metainterp_sd) graphpage.display() @@ -126,7 +135,7 @@ graphname = self.getgraphname(graphindex) if self.CLUSTERING: self.dotgen.emit('subgraph cluster%d {' % graphindex) - label = graph.get_display_text() + label = graph.get_display_text(self.memo) if label is not None: colorindex = self.highlight_graphs.get(graph, 0) if colorindex == 1: @@ -200,9 +209,10 @@ for op in self.all_operations: args = op.getarglist() + [op] for box in args: - if getattr(box, 'is_box', False): - boxes[box] = True + s = box.repr_short(self.memo) + if len(s) > 1 and s[0] in 'irf' and s[1:].isdigit(): + boxes[box] = s links = {} - for box in boxes: - links[str(box)] = repr(box), self.BOX_COLOR + for box, s in boxes.items(): + links.setdefault(s, (box.repr(self.memo), self.BOX_COLOR)) return links diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -506,8 +506,10 @@ def get_operations(self): return self.operations - def get_display_text(self): # for graphpage.py - return self.name + '\n' + repr(self.inputargs) + def get_display_text(self, memo): # for graphpage.py + return '%s\n[%s]' % ( + self.name, + ', '.join([box.repr(memo) for box in self.inputargs])) def show(self, errmsg=None): "NOT_RPYTHON" From noreply at buildbot.pypy.org Tue Sep 1 17:23:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 17:23:46 +0200 (CEST) Subject: [pypy-commit] pypy keys_with_hash: Close branch, ready to merge Message-ID: <20150901152346.073DF1C08B9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: keys_with_hash Changeset: r79349:a9c20f508e90 Date: 2015-09-01 14:46 +0200 http://bitbucket.org/pypy/pypy/changeset/a9c20f508e90/ Log: Close branch, ready to merge From noreply at buildbot.pypy.org Tue Sep 1 17:23:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 17:23:48 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge keys_with_hash Message-ID: <20150901152348.CF1E91C08B9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79350:872f1108d840 Date: 2015-09-01 14:50 +0200 http://bitbucket.org/pypy/pypy/changeset/872f1108d840/ Log: hg merge keys_with_hash Improve the performance of dict.update() and a bunch of methods from sets, by reusing the hash value stored in one dict when inspecting or changing another dict with that key. This is done with the help of new xxx_with_hash() functions in objectmodel that work for any RPython dict or r_dict. diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,12 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): @@ -989,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1020,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1105,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1125,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1152,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -520,26 +520,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -11,11 +12,13 @@ SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue, - s_Bool, s_None, unionof, add_knowntypedata, + s_Bool, s_None, s_Int, unionof, add_knowntypedata, HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray) from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -364,20 +367,19 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - at op.contains.register(SomeDict) -def contains_SomeDict(annotator, dct, element): - annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) - if annotator.annotation(dct)._is_empty(): +def dict_contains(s_dct, s_element): + s_dct.dictdef.generalize_key(s_element) + if s_dct._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool -contains_SomeDict.can_only_throw = _can_only_throw + + at op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + return dict_contains(annotator.annotation(dct), + annotator.annotation(element)) +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -401,16 +403,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -448,6 +456,12 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass @@ -460,6 +474,22 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -788,6 +788,71 @@ d = d.keys() return reversed(d) +def _expected_hash(d, key): + if isinstance(d, r_dict): + return d.key_hash(key) + else: + return compute_hash(key) + +def _iterkeys_with_hash_untranslated(d): + for k in d: + yield (k, _expected_hash(d, k)) + + at specialize.call_location() +def iterkeys_with_hash(d): + """Iterates (key, hash) pairs without recomputing the hash.""" + if not we_are_translated(): + return _iterkeys_with_hash_untranslated(d) + return d.iterkeys_with_hash() + +def _iteritems_with_hash_untranslated(d): + for k, v in d.iteritems(): + yield (k, v, _expected_hash(d, k)) + + at specialize.call_location() +def iteritems_with_hash(d): + """Iterates (key, value, keyhash) triples without recomputing the hash.""" + if not we_are_translated(): + return _iteritems_with_hash_untranslated(d) + return d.iteritems_with_hash() + + at specialize.call_location() +def contains_with_hash(d, key, h): + """Same as 'key in d'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + return key in d + return d.contains_with_hash(key, h) + + at specialize.call_location() +def setitem_with_hash(d, key, h, value): + """Same as 'd[key] = value'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + d[key] = value + return + d.setitem_with_hash(key, h, value) + + at specialize.call_location() +def getitem_with_hash(d, key, h): + """Same as 'd[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + return d[key] + return d.getitem_with_hash(key, h) + + at specialize.call_location() +def delitem_with_hash(d, key, h): + """Same as 'del d[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + del d[key] + return + d.delitem_with_hash(key, h) # ____________________________________________________________ diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -592,6 +592,97 @@ r = interpret(f, [29]) assert r == 1 +def test_iterkeys_with_hash(): + def f(i): + d = {i+.0: 5, i+.5: 6} + total = 0 + for k, h in iterkeys_with_hash(d): + total += k * h + total -= (i + 0.0) * compute_hash(i + 0.0) + total -= (i + 0.5) * compute_hash(i + 0.5) + return total + + assert f(29) == 0.0 + r = interpret(f, [29]) + assert r == 0.0 + +def test_iteritems_with_hash(): + def f(i): + d = {i+.0: 5, i+.5: 6} + total = 0 + for k, v, h in iteritems_with_hash(d): + total += k * h * v + total -= (i + 0.0) * compute_hash(i + 0.0) * 5 + total -= (i + 0.5) * compute_hash(i + 0.5) * 6 + return total + + assert f(29) == 0.0 + r = interpret(f, [29]) + assert r == 0.0 + +def test_contains_with_hash(): + def f(i): + d = {i+.5: 5} + assert contains_with_hash(d, i+.5, compute_hash(i+.5)) + assert not contains_with_hash(d, i+.3, compute_hash(i+.3)) + return 0 + + f(29) + interpret(f, [29]) + +def test_setitem_with_hash(): + def f(i): + d = {} + setitem_with_hash(d, i+.5, compute_hash(i+.5), 42) + setitem_with_hash(d, i+.6, compute_hash(i+.6), -612) + return d[i+.5] + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + +def test_getitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + return getitem_with_hash(d, i+.5, compute_hash(i+.5)) + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + +def test_delitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + try: + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + except KeyError: + pass + else: + raise AssertionError + return 0 + + f(29) + interpret(f, [27]) + +def test_rdict_with_hash(): + def f(i): + d = r_dict(strange_key_eq, strange_key_hash) + h = strange_key_hash("abc") + assert h == strange_key_hash("aXX") and strange_key_eq("abc", "aXX") + setitem_with_hash(d, "abc", h, i) + assert getitem_with_hash(d, "aXX", h) == i + try: + getitem_with_hash(d, "bYY", strange_key_hash("bYY")) + except KeyError: + pass + else: + raise AssertionError + return 0 + + assert f(29) == 0 + interpret(f, [27]) + def test_import_from_mixin(): class M: # old-style def f(self): pass diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -335,6 +335,14 @@ hop.exception_cannot_occur() return DictIteratorRepr(self, "items").newiter(hop) + def rtype_method_iterkeys_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "keys_with_hash").newiter(hop) + + def rtype_method_iteritems_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "items_with_hash").newiter(hop) + def rtype_method_clear(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() @@ -358,6 +366,41 @@ v_res = hop.gendirectcall(target, *v_args) return self.recast_value(hop.llops, v_res) + def rtype_method_contains_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs(self, self.key_repr, + lltype.Signed) + hop.exception_is_here() + return hop.gendirectcall(ll_dict_contains_with_hash, + v_dict, v_key, v_hash) + + def rtype_method_setitem_with_hash(self, hop): + v_dict, v_key, v_hash, v_value = hop.inputargs( + self, self.key_repr, lltype.Signed, self.value_repr) + if self.custom_eq_hash: + hop.exception_is_here() + else: + hop.exception_cannot_occur() + hop.gendirectcall(ll_dict_setitem_with_hash, + v_dict, v_key, v_hash, v_value) + + def rtype_method_getitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + v_res = hop.gendirectcall(ll_dict_getitem_with_hash, + v_dict, v_key, v_hash) + return self.recast_value(hop.llops, v_res) + + def rtype_method_delitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -373,7 +416,7 @@ if not r_dict.custom_eq_hash: hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) + hop.gendirectcall(ll_dict_delitem, v_dict, v_key) def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr) @@ -541,16 +584,21 @@ return bool(d) and d.num_live_items != 0 def ll_dict_getitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) + return ll_dict_getitem_with_hash(d, key, d.keyhash(key)) + +def ll_dict_getitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_LOOKUP) if index >= 0: return d.entries[index].value else: raise KeyError def ll_dict_setitem(d, key, value): - hash = d.keyhash(key) + ll_dict_setitem_with_hash(d, key, d.keyhash(key), value) + +def ll_dict_setitem_with_hash(d, key, hash, value): index = d.lookup_function(d, key, hash, FLAG_STORE) - return _ll_dict_setitem_lookup_done(d, key, value, hash, index) + _ll_dict_setitem_lookup_done(d, key, value, hash, index) # It may be safe to look inside always, it has a few branches though, and their # frequencies needs to be investigated. @@ -731,7 +779,10 @@ def ll_dict_delitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_DELETE) + ll_dict_delitem_with_hash(d, key, d.keyhash(key)) + +def ll_dict_delitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_DELETE) if index < 0: raise KeyError _ll_dict_del(d, index) @@ -1214,7 +1265,10 @@ ll_dict_items = _make_ll_keys_values_items('items') def ll_dict_contains(d, key): - i = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) + return ll_dict_contains_with_hash(d, key, d.keyhash(key)) + +def ll_dict_contains_with_hash(d, key, hash): + i = d.lookup_function(d, key, hash, FLAG_LOOKUP) return i >= 0 def _ll_getnextitem(dic): diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py --- a/rpython/rtyper/rdict.py +++ b/rpython/rtyper/rdict.py @@ -72,20 +72,14 @@ return hop.gendirectcall(self.ll_dictiter, citerptr, v_dict) def rtype_next(self, hop): - variant = self.variant v_iter, = hop.inputargs(self) # record that we know about these two possible exceptions hop.has_implicit_exception(StopIteration) hop.has_implicit_exception(RuntimeError) hop.exception_is_here() v_index = hop.gendirectcall(self._ll_dictnext, v_iter) - if variant == 'items' and hop.r_result.lowleveltype != lltype.Void: - # this allocates the tuple for the result, directly in the function - # where it will be used (likely). This will let it be removed. - c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) - cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) - v_result = hop.genop('malloc', [c1, cflags], - resulttype = hop.r_result.lowleveltype) + # + # read 'iter.dict.entries' DICT = self.lowleveltype.TO.dict c_dict = hop.inputconst(lltype.Void, 'dict') v_dict = hop.genop('getfield', [v_iter, c_dict], resulttype=DICT) @@ -93,32 +87,61 @@ c_entries = hop.inputconst(lltype.Void, 'entries') v_entries = hop.genop('getfield', [v_dict, c_entries], resulttype=ENTRIES) - if variant != 'values': - KEY = ENTRIES.TO.OF.key - c_key = hop.inputconst(lltype.Void, 'key') - v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], - resulttype=KEY) - if variant != 'keys' and variant != 'reversed': - VALUE = ENTRIES.TO.OF.value - c_value = hop.inputconst(lltype.Void, 'value') - v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], - resulttype=VALUE) - if variant == 'keys' or variant == 'reversed': - return self.r_dict.recast_key(hop.llops, v_key) - elif variant == 'values': - return self.r_dict.recast_value(hop.llops, v_value) - elif hop.r_result.lowleveltype == lltype.Void: + # call the correct variant_*() method + method = getattr(self, 'variant_' + self.variant) + return method(hop, ENTRIES, v_entries, v_index) + + def get_tuple_result(self, hop, items_v): + # this allocates the tuple for the result, directly in the function + # where it will be used (likely). This will let it be removed. + if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) - else: - assert variant == 'items' - ITEM0 = v_result.concretetype.TO.item0 - ITEM1 = v_result.concretetype.TO.item1 - if ITEM0 != v_key.concretetype: - v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0) - if ITEM1 != v_value.concretetype: - v_value = hop.genop('cast_pointer', [v_value], resulttype=ITEM1) - c_item0 = hop.inputconst(lltype.Void, 'item0') - c_item1 = hop.inputconst(lltype.Void, 'item1') - hop.genop('setfield', [v_result, c_item0, v_key]) - hop.genop('setfield', [v_result, c_item1, v_value]) - return v_result + c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) + cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) + v_result = hop.genop('malloc', [c1, cflags], + resulttype = hop.r_result.lowleveltype) + for i, v_item in enumerate(items_v): + ITEM = getattr(v_result.concretetype.TO, 'item%d' % i) + if ITEM != v_item.concretetype: + assert isinstance(ITEM, lltype.Ptr) + v_item = hop.genop('cast_pointer', [v_item], resulttype=ITEM) + c_item = hop.inputconst(lltype.Void, 'item%d' % i) + hop.genop('setfield', [v_result, c_item, v_item]) + return v_result + + def variant_keys(self, hop, ENTRIES, v_entries, v_index): + KEY = ENTRIES.TO.OF.key + c_key = hop.inputconst(lltype.Void, 'key') + v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], + resulttype=KEY) + return self.r_dict.recast_key(hop.llops, v_key) + + variant_reversed = variant_keys + + def variant_values(self, hop, ENTRIES, v_entries, v_index): + VALUE = ENTRIES.TO.OF.value + c_value = hop.inputconst(lltype.Void, 'value') + v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], + resulttype=VALUE) + return self.r_dict.recast_value(hop.llops, v_value) + + def variant_items(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value)) + + def variant_hashes(self, hop, ENTRIES, v_entries, v_index): + # there is not really a variant 'hashes', but this method is + # convenient for the following variants + return hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) + + def variant_keys_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_hash)) + + def variant_items_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value, v_hash)) From noreply at buildbot.pypy.org Tue Sep 1 18:29:11 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 1 Sep 2015 18:29:11 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: test and fix for rare bug when triggering minor GC in hashtable_lookup Message-ID: <20150901162911.EF0A81C0359@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: use-gcc Changeset: r1950:58f9e6d56296 Date: 2015-09-01 16:58 +0200 http://bitbucket.org/pypy/stmgc/changeset/58f9e6d56296/ Log: test and fix for rare bug when triggering minor GC in hashtable_lookup It was possible that allocating the entry would trigger a minor GC. Then, there is an old hashtable with a young entry that may not get traced in the next collection. I chose to make fall back to a preexisting entry in that case, but another way would be to make stm_hashtable_write_entry ensure that there is an stm_write() on the hobj if 'entry' is young. diff --git a/c8/stm/core.h b/c8/stm/core.h --- a/c8/stm/core.h +++ b/c8/stm/core.h @@ -267,14 +267,6 @@ return stm_object_pages + segment_num * (NB_PAGES * 4096UL); } -static inline long get_num_segment_containing_address(char *addr) -{ - uintptr_t delta = addr - stm_object_pages; - uintptr_t result = delta / (NB_PAGES * 4096UL); - assert(result < NB_SEGMENTS); - return result; -} - static inline struct stm_segment_info_s *get_segment(long segment_num) { return (struct stm_segment_info_s *)REAL_ADDRESS( diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -285,7 +285,8 @@ if (rc > 6) { /* we can only enter here once! If we allocate stuff, we may run the GC, and so 'hashtableobj' might move afterwards. */ - if (_is_in_nursery(hashtableobj)) { + if (_is_in_nursery(hashtableobj) + && will_allocate_in_nursery(sizeof(stm_hashtable_entry_t))) { /* this also means that the hashtable is from this transaction and not visible to other segments yet, so the new entry can be nursery-allocated. */ @@ -325,9 +326,6 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; - /* make sure .object is NULL in all segments before - "publishing" the entry in the hashtable: */ - write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ @@ -362,6 +360,9 @@ stm_write((object_t *)entry); + /* this restriction may be lifted, see test_new_entry_if_nursery_full: */ + assert(IMPLY(_is_young((object_t *)entry), _is_young(hobj))); + uintptr_t i = list_count(STM_PSEGMENT->modified_old_objects); if (i > 0 && list_item(STM_PSEGMENT->modified_old_objects, i - 3) == (uintptr_t)entry) { @@ -486,7 +487,7 @@ objects in the segment of the running transaction. Otherwise, the base case is to read them all from segment zero. */ - long segnum = get_num_segment_containing_address((char *)hobj); + long segnum = get_segment_of_linear_address((char *)hobj); if (!IS_OVERFLOW_OBJ(get_priv_segment(segnum), hobj)) segnum = 0; diff --git a/c8/stm/nursery.h b/c8/stm/nursery.h --- a/c8/stm/nursery.h +++ b/c8/stm/nursery.h @@ -27,6 +27,20 @@ get_priv_segment(other_segment_num)->safe_point != SP_RUNNING); } +static inline bool will_allocate_in_nursery(size_t size_rounded_up) { + OPT_ASSERT(size_rounded_up >= 16); + OPT_ASSERT((size_rounded_up & 7) == 0); + + if (UNLIKELY(size_rounded_up >= _STM_FAST_ALLOC)) + return false; + + stm_char *p = STM_SEGMENT->nursery_current; + stm_char *end = p + size_rounded_up; + if (UNLIKELY((uintptr_t)end > STM_SEGMENT->nursery_end)) + return false; + return true; +} + #define must_abort() is_abort(STM_SEGMENT->nursery_end) static object_t *find_shadow(object_t *obj); diff --git a/c8/test/support.py b/c8/test/support.py --- a/c8/test/support.py +++ b/c8/test/support.py @@ -12,6 +12,8 @@ #define _STM_FAST_ALLOC ... #define _STM_CARD_SIZE ... #define _STM_CARD_MARKED ... +#define STM_GC_NURSERY ... +#define SIZEOF_HASHTABLE_ENTRY ... typedef struct { ...; @@ -209,6 +211,9 @@ object_t *hashtable_read_result; bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key, object_t *nvalue, stm_thread_local_t *tl); +stm_hashtable_entry_t *stm_hashtable_lookup(object_t *hashtableobj, + stm_hashtable_t *hashtable, + uintptr_t index); long stm_hashtable_length_upper_bound(stm_hashtable_t *); uint32_t stm_hashtable_entry_userdata; void stm_hashtable_tracefn(struct object_s *, stm_hashtable_t *, @@ -256,6 +261,7 @@ typedef TLPREFIX struct myobj_s myobj_t; #define SIZEOF_MYOBJ sizeof(struct myobj_s) +#define SIZEOF_HASHTABLE_ENTRY sizeof(struct stm_hashtable_entry_s) int _stm_get_flags(object_t *obj) { return obj->stm_flags; @@ -580,6 +586,7 @@ ('STM_NO_COND_WAIT', '1'), ('STM_DEBUGPRINT', '1'), ('_STM_NURSERY_ZEROED', '1'), + ('STM_GC_NURSERY', '128'), # KB ('GC_N_SMALL_REQUESTS', str(GC_N_SMALL_REQUESTS)), #check ], undef_macros=['NDEBUG'], @@ -600,7 +607,8 @@ CARD_MARKED = lib._STM_CARD_MARKED CARD_MARKED_OLD = lib._stm_get_transaction_read_version lib.stm_hashtable_entry_userdata = 421418 - +NURSERY_SIZE = lib.STM_GC_NURSERY * 1024 # bytes +SIZEOF_HASHTABLE_ENTRY = lib.SIZEOF_HASHTABLE_ENTRY class Conflict(Exception): pass @@ -662,14 +670,20 @@ lib._set_type_id(o, tid) return o +SIZEOF_HASHTABLE_OBJ = 16 + lib.SIZEOF_MYOBJ def stm_allocate_hashtable(): o = lib.stm_allocate(16) + assert is_in_nursery(o) tid = 421419 lib._set_type_id(o, tid) h = lib.stm_hashtable_create() lib._set_hashtable(o, h) return o +def hashtable_lookup(hto, ht, idx): + return ffi.cast("object_t*", + lib.stm_hashtable_lookup(hto, ht, idx)) + def get_hashtable(o): assert lib._get_type_id(o) == 421419 h = lib._get_hashtable(o) diff --git a/c8/test/test_hashtable.py b/c8/test/test_hashtable.py --- a/c8/test/test_hashtable.py +++ b/c8/test/test_hashtable.py @@ -354,6 +354,50 @@ stm_major_collect() # to get rid of the hashtable object + def test_new_entry_if_nursery_full(self): + self.start_transaction() + tl0 = self.tls[self.current_thread] + # make sure we fill the nursery *exactly* so that + # the last entry allocation triggers a minor GC + # and needs to allocate preexisting outside the nursery: + SMALL = 24 + lib.SIZEOF_MYOBJ + assert (NURSERY_SIZE - SIZEOF_HASHTABLE_OBJ) % SMALL < SIZEOF_HASHTABLE_ENTRY + to_alloc = (NURSERY_SIZE - SIZEOF_HASHTABLE_OBJ) // SMALL + for i in range(to_alloc): + stm_allocate(SMALL) + h = self.allocate_hashtable() + assert is_in_nursery(h) + self.push_root(h) + # would trigger minor GC when allocating 'entry' in nursery: + entry = hashtable_lookup(h, get_hashtable(h), 123) + h = self.pop_root() + self.push_root(h) + assert is_in_nursery(h) # didn't trigger minor-gc, since entry allocated outside + assert not is_in_nursery(entry) + assert htget(h, 123) == ffi.NULL + htset(h, 123, h, tl0) + + # stm_write(h) - the whole thing may be fixed also by ensuring + # the hashtable gets retraced in minor-GC if stm_hashtable_write_entry + # detects the 'entry' to be young (and hobj being old) + + stm_minor_collect() + h = self.pop_root() + assert htget(h, 123) == h + entry2 = hashtable_lookup(h, get_hashtable(h), 123) + assert entry == entry2 + assert not is_in_nursery(h) + assert not is_in_nursery(entry2) + + # get rid of ht: + self.commit_transaction() + self.start_transaction() + stm_major_collect() + self.commit_transaction() + + + + class TestRandomHashtable(BaseTestHashtable): def setup_method(self, meth): From noreply at buildbot.pypy.org Tue Sep 1 18:55:56 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 1 Sep 2015 18:55:56 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: import stmgc with hashtable fixes Message-ID: <20150901165556.C49131C08B9@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79353:9ef3acdbc233 Date: 2015-09-01 17:31 +0200 http://bitbucket.org/pypy/pypy/changeset/9ef3acdbc233/ Log: import stmgc with hashtable fixes diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -08c773f2b6ef +58f9e6d56296 diff --git a/rpython/translator/stm/src_stm/stm/core.h b/rpython/translator/stm/src_stm/stm/core.h --- a/rpython/translator/stm/src_stm/stm/core.h +++ b/rpython/translator/stm/src_stm/stm/core.h @@ -267,14 +267,6 @@ return stm_object_pages + segment_num * (NB_PAGES * 4096UL); } -static inline long get_num_segment_containing_address(char *addr) -{ - uintptr_t delta = addr - stm_object_pages; - uintptr_t result = delta / (NB_PAGES * 4096UL); - assert(result < NB_SEGMENTS); - return result; -} - static inline struct stm_segment_info_s *get_segment(long segment_num) { return (struct stm_segment_info_s *)REAL_ADDRESS( diff --git a/rpython/translator/stm/src_stm/stm/finalizer.c b/rpython/translator/stm/src_stm/stm/finalizer.c --- a/rpython/translator/stm/src_stm/stm/finalizer.c +++ b/rpython/translator/stm/src_stm/stm/finalizer.c @@ -486,12 +486,7 @@ LIST_FREE(f->run_finalizers); } -/* XXX: can there be a race between _invoke_general_finalizers - and _commit_finalizer on g_finalizers (+other places?)? - XXX: what happens in _execute_finalizer if the transaction - conflicts (or fails to become inevitable) in a finalizer? - (the run_finalizers list is half-way cleared?) - XXX: according to translator.backendopt.finalizer, getfield_gc +/* XXX: according to translator.backendopt.finalizer, getfield_gc for primitive types is a safe op in light finalizers. I don't think that's correct in general (maybe if getfield on *dying obj*). diff --git a/rpython/translator/stm/src_stm/stm/hashtable.c b/rpython/translator/stm/src_stm/stm/hashtable.c --- a/rpython/translator/stm/src_stm/stm/hashtable.c +++ b/rpython/translator/stm/src_stm/stm/hashtable.c @@ -285,7 +285,8 @@ if (rc > 6) { /* we can only enter here once! If we allocate stuff, we may run the GC, and so 'hashtableobj' might move afterwards. */ - if (_is_in_nursery(hashtableobj)) { + if (_is_in_nursery(hashtableobj) + && will_allocate_in_nursery(sizeof(stm_hashtable_entry_t))) { /* this also means that the hashtable is from this transaction and not visible to other segments yet, so the new entry can be nursery-allocated. */ @@ -325,9 +326,6 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; - /* make sure .object is NULL in all segments before - "publishing" the entry in the hashtable: */ - write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ @@ -362,6 +360,9 @@ stm_write((object_t *)entry); + /* this restriction may be lifted, see test_new_entry_if_nursery_full: */ + assert(IMPLY(_is_young((object_t *)entry), _is_young(hobj))); + uintptr_t i = list_count(STM_PSEGMENT->modified_old_objects); if (i > 0 && list_item(STM_PSEGMENT->modified_old_objects, i - 3) == (uintptr_t)entry) { @@ -486,7 +487,7 @@ objects in the segment of the running transaction. Otherwise, the base case is to read them all from segment zero. */ - long segnum = get_num_segment_containing_address((char *)hobj); + long segnum = get_segment_of_linear_address((char *)hobj); if (!IS_OVERFLOW_OBJ(get_priv_segment(segnum), hobj)) segnum = 0; diff --git a/rpython/translator/stm/src_stm/stm/nursery.h b/rpython/translator/stm/src_stm/stm/nursery.h --- a/rpython/translator/stm/src_stm/stm/nursery.h +++ b/rpython/translator/stm/src_stm/stm/nursery.h @@ -27,6 +27,20 @@ get_priv_segment(other_segment_num)->safe_point != SP_RUNNING); } +static inline bool will_allocate_in_nursery(size_t size_rounded_up) { + OPT_ASSERT(size_rounded_up >= 16); + OPT_ASSERT((size_rounded_up & 7) == 0); + + if (UNLIKELY(size_rounded_up >= _STM_FAST_ALLOC)) + return false; + + stm_char *p = STM_SEGMENT->nursery_current; + stm_char *end = p + size_rounded_up; + if (UNLIKELY((uintptr_t)end > STM_SEGMENT->nursery_end)) + return false; + return true; +} + #define must_abort() is_abort(STM_SEGMENT->nursery_end) static object_t *find_shadow(object_t *obj); From noreply at buildbot.pypy.org Tue Sep 1 18:58:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:58:54 +0200 (CEST) Subject: [pypy-commit] pypy default: add a passing test Message-ID: <20150901165854.3F3411C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79354:c723aedd0d05 Date: 2015-09-01 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/c723aedd0d05/ Log: add a passing test 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 @@ -8666,5 +8666,24 @@ """ self.optimize_loop(ops, expected, expected_short=expected_short) + def test_pass_both_short_preamble_and_arg(self): + ops = """ + [i0, i1] + i2 = int_add(i0, 1) + jump(i0, i2) + """ + expected = """ + [i0, i1, i2] + jump(i0, i2, i2) + """ + preamble = """ + [i0, i1] + i2 = int_add(i0, 1) + i3 = same_as(i2) + jump(i0, i2, i3) + """ + self.optimize_loop(ops, expected, preamble) + + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -315,6 +315,7 @@ # Construct jumpargs from the virtual state original_jumpargs = jumpop.getarglist()[:] values = [self.getvalue(arg) for arg in jumpop.getarglist()] + try: jumpargs = virtual_state.make_inputargs(values, self.optimizer) except BadVirtualState: From noreply at buildbot.pypy.org Tue Sep 1 18:58:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:58:56 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: add a failing test Message-ID: <20150901165856.750B31C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79355:6c72b2fe2180 Date: 2015-09-01 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/6c72b2fe2180/ Log: add a failing test 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 @@ -8685,5 +8685,23 @@ """ self.optimize_loop(ops, ops) + def test_pass_both_short_preamble_and_arg(self): + ops = """ + [i0, i1] + i2 = int_add(i0, 1) + jump(i0, i2) + """ + expected = """ + [i0, i1, i2] + jump(i0, i1, i2) + """ + preamble = """ + [i0, i1] + i2 = int_add(i0, 1) + i3 = same_as_i(i2) + jump(i0, i2, i3) + """ + self.optimize_loop(ops, expected, preamble) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -138,7 +138,6 @@ return (UnrollInfo(target_token, label_op, [], self.optimizer.quasi_immutable_deps), self.optimizer._newoperations) - #return new_virtual_state, self.optimizer._newoperations return (UnrollInfo(target_token, label_op, extra_same_as, self.optimizer.quasi_immutable_deps), self.optimizer._newoperations) From noreply at buildbot.pypy.org Tue Sep 1 18:58:58 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:58:58 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: replace raise Exception with also invalid code, but slightly better Message-ID: <20150901165858.A94371C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79356:ff9c92e75aa6 Date: 2015-09-01 17:28 +0200 http://bitbucket.org/pypy/pypy/changeset/ff9c92e75aa6/ Log: replace raise Exception with also invalid code, but slightly better diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -326,9 +326,9 @@ loop_jitcell_token = metainterp.get_procedure_token(greenkey) assert loop_jitcell_token - end_label = ResOperation(rop.LABEL, inputargs, + end_label = ResOperation(rop.LABEL, inputargs[:], descr=loop_jitcell_token) - jump_op = ResOperation(rop.JUMP, jumpargs, descr=loop_jitcell_token) + jump_op = ResOperation(rop.JUMP, jumpargs[:], descr=loop_jitcell_token) enable_opts = jitdriver_sd.warmstate.enable_opts ops = history.operations[start:] call_pure_results = metainterp.call_pure_results @@ -339,23 +339,37 @@ loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: - # Fall back on jumping to preamble - raise Exception("think about it") - return None + xxx + # Fall back on jumping directly to preamble + jump_op = ResOperation(rop.JUMP, inputargs[:], + descr=loop_jitcell_token.target_tokens[0]) + loop_data = SimpleCompileData(end_label, [jump_op], call_pure_results, + enable_opts) + try: + loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, + loop_data) + except InvalidLoop: + return None + loop = partial_trace + loop.original_jitcell_token = loop_jitcell_token + loop.operations = loop_ops[:] + loop.inputargs = loop_info.inputargs[:] + loop.check_consistency() + else: - loop = partial_trace - loop.original_jitcell_token = loop_jitcell_token - loop.operations = (loop.operations + loop_info.extra_same_as + - [loop_info.label_op] - + loop_ops) + loop = partial_trace + loop.original_jitcell_token = loop_jitcell_token + loop.operations = (loop.operations + loop_info.extra_same_as + + [loop_info.label_op] + + loop_ops) - quasi_immutable_deps = {} - if loop_info.quasi_immutable_deps: - quasi_immutable_deps.update(loop_info.quasi_immutable_deps) - if start_state.quasi_immutable_deps: - quasi_immutable_deps.update(start_state.quasi_immutable_deps) - if quasi_immutable_deps: - loop.quasi_immutable_deps = quasi_immutable_deps + quasi_immutable_deps = {} + if loop_info.quasi_immutable_deps: + quasi_immutable_deps.update(loop_info.quasi_immutable_deps) + if start_state.quasi_immutable_deps: + quasi_immutable_deps.update(start_state.quasi_immutable_deps) + if quasi_immutable_deps: + loop.quasi_immutable_deps = quasi_immutable_deps target_token = loop.operations[-1].getdescr() resumekey.compile_and_attach(metainterp, loop, inputargs) From noreply at buildbot.pypy.org Tue Sep 1 18:59:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:59:00 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: this is what the test is supposed to be doing Message-ID: <20150901165900.DC30E1C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79357:57b489c27fa6 Date: 2015-09-01 17:30 +0200 http://bitbucket.org/pypy/pypy/changeset/57b489c27fa6/ Log: this is what the test is supposed to be doing 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 @@ -8693,7 +8693,7 @@ """ expected = """ [i0, i1, i2] - jump(i0, i1, i2) + jump(i0, i2, i2) """ preamble = """ [i0, i1] From noreply at buildbot.pypy.org Tue Sep 1 18:59:03 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:59:03 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150901165903.2FF481C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79358:74406ff51f52 Date: 2015-09-01 17:30 +0200 http://bitbucket.org/pypy/pypy/changeset/74406ff51f52/ Log: merge diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -789,6 +789,7 @@ new_loop.original_jitcell_token = metainterp.resumekey_original_loop_token inputargs = new_loop.inputargs if not we_are_translated(): + self._debug_subinputargs = new_loop.inputargs self._debug_suboperations = new_loop.operations propagate_original_jitcell_token(new_loop) send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata, diff --git a/rpython/jit/metainterp/graphpage.py b/rpython/jit/metainterp/graphpage.py --- a/rpython/jit/metainterp/graphpage.py +++ b/rpython/jit/metainterp/graphpage.py @@ -4,11 +4,21 @@ from rpython.jit.metainterp.resoperation import rop class SubGraph: - def __init__(self, suboperations): - self.suboperations = suboperations + def __init__(self, op): + self.failargs = op.getfailargs() + self.subinputargs = op.getdescr()._debug_subinputargs + self.suboperations = op.getdescr()._debug_suboperations def get_operations(self): return self.suboperations - def get_display_text(self): + def get_display_text(self, memo): + # copy the display of variables in this subgraph (a bridge) + # so that they match variables in the parent graph across the + # guard failure + for failarg, inputarg in zip(self.failargs, self.subinputargs): + try: + memo[inputarg] = memo[failarg] + except KeyError: + pass return None def display_procedures(procedures, errmsg=None, highlight_procedures={}, metainterp_sd=None): @@ -17,8 +27,7 @@ for graph, highlight in graphs: for op in graph.get_operations(): if is_interesting_guard(op): - graphs.append((SubGraph(op.getdescr()._debug_suboperations), - highlight)) + graphs.append((SubGraph(op), highlight)) graphpage = ResOpGraphPage(graphs, errmsg, metainterp_sd) graphpage.display() @@ -126,7 +135,7 @@ graphname = self.getgraphname(graphindex) if self.CLUSTERING: self.dotgen.emit('subgraph cluster%d {' % graphindex) - label = graph.get_display_text() + label = graph.get_display_text(self.memo) if label is not None: colorindex = self.highlight_graphs.get(graph, 0) if colorindex == 1: @@ -200,9 +209,10 @@ for op in self.all_operations: args = op.getarglist() + [op] for box in args: - if getattr(box, 'is_box', False): - boxes[box] = True + s = box.repr_short(self.memo) + if len(s) > 1 and s[0] in 'irf' and s[1:].isdigit(): + boxes[box] = s links = {} - for box in boxes: - links[str(box)] = repr(box), self.BOX_COLOR + for box, s in boxes.items(): + links.setdefault(s, (box.repr(self.memo), self.BOX_COLOR)) return links diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -506,8 +506,10 @@ def get_operations(self): return self.operations - def get_display_text(self): # for graphpage.py - return self.name + '\n' + repr(self.inputargs) + def get_display_text(self, memo): # for graphpage.py + return '%s\n[%s]' % ( + self.name, + ', '.join([box.repr(memo) for box in self.inputargs])) def show(self, errmsg=None): "NOT_RPYTHON" From noreply at buildbot.pypy.org Tue Sep 1 18:59:06 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 18:59:06 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20150901165906.92C2B1C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79359:ef6c662bf331 Date: 2015-09-01 17:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ef6c662bf331/ Log: merge diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -429,7 +430,7 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,12 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): @@ -989,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1020,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1105,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1125,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1152,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -520,26 +520,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -11,11 +12,13 @@ SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue, - s_Bool, s_None, unionof, add_knowntypedata, + s_Bool, s_None, s_Int, unionof, add_knowntypedata, HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray) from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -364,20 +367,19 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - at op.contains.register(SomeDict) -def contains_SomeDict(annotator, dct, element): - annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) - if annotator.annotation(dct)._is_empty(): +def dict_contains(s_dct, s_element): + s_dct.dictdef.generalize_key(s_element) + if s_dct._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool -contains_SomeDict.can_only_throw = _can_only_throw + + at op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + return dict_contains(annotator.annotation(dct), + annotator.annotation(element)) +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -401,16 +403,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -448,6 +456,12 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass @@ -460,6 +474,22 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/doc/conf.py b/rpython/doc/conf.py --- a/rpython/doc/conf.py +++ b/rpython/doc/conf.py @@ -68,7 +68,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -114,10 +114,7 @@ def build_frame_realloc_slowpath(self): mc = codebuf.MachineCodeBlockWrapper() self._push_all_regs_to_frame(mc, [], self.cpu.supports_floats) - # this is the gcmap stored by push_gcmap(mov=True) in _check_stack_frame - mc.MOV_rs(ecx.value, WORD) - gcmap_ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.MOV_br(gcmap_ofs, ecx.value) + # the caller already did push_gcmap(store=True) if IS_X86_64: mc.MOV_rs(esi.value, WORD*2) @@ -147,7 +144,7 @@ self._load_shadowstack_top_in_ebx(mc, gcrootmap) mc.MOV_mr((ebx.value, -WORD), eax.value) - mc.MOV_bi(gcmap_ofs, 0) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], self.cpu.supports_floats) mc.RET() self._frame_realloc_slowpath = mc.materialize(self.cpu, []) @@ -164,6 +161,7 @@ # the end of this function. self._push_all_regs_to_frame(mc, cond_call_register_arguments + [eax], supports_floats, callee_only) + # the caller already did push_gcmap(store=True) if IS_X86_64: mc.SUB(esp, imm(WORD)) # alignment self.set_extra_stack_depth(mc, 2 * WORD) @@ -182,8 +180,8 @@ mc.ADD(esp, imm(WORD * 7)) self.set_extra_stack_depth(mc, 0) self._reload_frame_if_necessary(mc, align_stack=True) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only) - self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller mc.RET() return mc.materialize(self.cpu, []) @@ -203,10 +201,7 @@ assert kind in ['fixed', 'str', 'unicode', 'var'] mc = codebuf.MachineCodeBlockWrapper() self._push_all_regs_to_frame(mc, [eax, edi], self.cpu.supports_floats) - # store the gc pattern - ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.MOV_rs(ecx.value, WORD) - mc.MOV_br(ofs, ecx.value) + # the caller already did push_gcmap(store=True) # if kind == 'fixed': addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() @@ -258,8 +253,7 @@ self.set_extra_stack_depth(mc, 0) self._pop_all_regs_from_frame(mc, [eax, edi], self.cpu.supports_floats) mc.MOV(edi, heap(nursery_free_adr)) # load this in EDI - # clear the gc pattern - mc.MOV_bi(ofs, 0) + self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller mc.RET() # # If the slowpath malloc failed, we raise a MemoryError that @@ -646,7 +640,7 @@ jg_location = mc.get_relative_pos() mc.MOV_si(WORD, 0xffffff) # force writing 32 bit ofs2 = mc.get_relative_pos() - 4 - self.push_gcmap(mc, gcmap, mov=True) + self.push_gcmap(mc, gcmap, store=True) mc.CALL(imm(self._frame_realloc_slowpath)) # patch the JG above offset = mc.get_relative_pos() - jg_location @@ -1797,12 +1791,9 @@ self.mc.JMP(imm(target)) return startpos - def push_gcmap(self, mc, gcmap, push=False, mov=False, store=False): + def push_gcmap(self, mc, gcmap, push=False, store=False): if push: mc.PUSH(imm(rffi.cast(lltype.Signed, gcmap))) - elif mov: - mc.MOV(RawEspLoc(0, REF), - imm(rffi.cast(lltype.Signed, gcmap))) else: assert store ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') @@ -2280,7 +2271,7 @@ self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later jmp_adr = self.mc.get_relative_pos() # save the gcmap - self.push_gcmap(self.mc, gcmap, mov=True) + self.push_gcmap(self.mc, gcmap, store=True) self.mc.CALL(imm(follow_jump(self.malloc_slowpath))) offset = self.mc.get_relative_pos() - jmp_adr assert 0 < offset <= 127 @@ -2301,7 +2292,7 @@ self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later jmp_adr = self.mc.get_relative_pos() # save the gcmap - self.push_gcmap(self.mc, gcmap, mov=True) + self.push_gcmap(self.mc, gcmap, store=True) self.mc.CALL(imm(follow_jump(self.malloc_slowpath))) offset = self.mc.get_relative_pos() - jmp_adr assert 0 < offset <= 127 @@ -2354,7 +2345,7 @@ assert 0 < offset <= 127 self.mc.overwrite(jmp_adr0-1, chr(offset)) # save the gcmap - self.push_gcmap(self.mc, gcmap, mov=True) # mov into RawEspLoc(0) + self.push_gcmap(self.mc, gcmap, store=True) if kind == rewrite.FLAG_ARRAY: self.mc.MOV_si(WORD, itemsize) self.mc.MOV(edi, lengthloc) diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -788,6 +788,71 @@ d = d.keys() return reversed(d) +def _expected_hash(d, key): + if isinstance(d, r_dict): + return d.key_hash(key) + else: + return compute_hash(key) + +def _iterkeys_with_hash_untranslated(d): + for k in d: + yield (k, _expected_hash(d, k)) + + at specialize.call_location() +def iterkeys_with_hash(d): + """Iterates (key, hash) pairs without recomputing the hash.""" + if not we_are_translated(): + return _iterkeys_with_hash_untranslated(d) + return d.iterkeys_with_hash() + +def _iteritems_with_hash_untranslated(d): + for k, v in d.iteritems(): + yield (k, v, _expected_hash(d, k)) + + at specialize.call_location() +def iteritems_with_hash(d): + """Iterates (key, value, keyhash) triples without recomputing the hash.""" + if not we_are_translated(): + return _iteritems_with_hash_untranslated(d) + return d.iteritems_with_hash() + + at specialize.call_location() +def contains_with_hash(d, key, h): + """Same as 'key in d'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + return key in d + return d.contains_with_hash(key, h) + + at specialize.call_location() +def setitem_with_hash(d, key, h, value): + """Same as 'd[key] = value'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + d[key] = value + return + d.setitem_with_hash(key, h, value) + + at specialize.call_location() +def getitem_with_hash(d, key, h): + """Same as 'd[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + return d[key] + return d.getitem_with_hash(key, h) + + at specialize.call_location() +def delitem_with_hash(d, key, h): + """Same as 'del d[key]'. The extra argument is the hash. Use this only + if you got the hash just now from some other ..._with_hash() function.""" + if not we_are_translated(): + assert _expected_hash(d, key) == h + del d[key] + return + d.delitem_with_hash(key, h) # ____________________________________________________________ diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py --- a/rpython/rlib/test/test_objectmodel.py +++ b/rpython/rlib/test/test_objectmodel.py @@ -592,6 +592,97 @@ r = interpret(f, [29]) assert r == 1 +def test_iterkeys_with_hash(): + def f(i): + d = {i+.0: 5, i+.5: 6} + total = 0 + for k, h in iterkeys_with_hash(d): + total += k * h + total -= (i + 0.0) * compute_hash(i + 0.0) + total -= (i + 0.5) * compute_hash(i + 0.5) + return total + + assert f(29) == 0.0 + r = interpret(f, [29]) + assert r == 0.0 + +def test_iteritems_with_hash(): + def f(i): + d = {i+.0: 5, i+.5: 6} + total = 0 + for k, v, h in iteritems_with_hash(d): + total += k * h * v + total -= (i + 0.0) * compute_hash(i + 0.0) * 5 + total -= (i + 0.5) * compute_hash(i + 0.5) * 6 + return total + + assert f(29) == 0.0 + r = interpret(f, [29]) + assert r == 0.0 + +def test_contains_with_hash(): + def f(i): + d = {i+.5: 5} + assert contains_with_hash(d, i+.5, compute_hash(i+.5)) + assert not contains_with_hash(d, i+.3, compute_hash(i+.3)) + return 0 + + f(29) + interpret(f, [29]) + +def test_setitem_with_hash(): + def f(i): + d = {} + setitem_with_hash(d, i+.5, compute_hash(i+.5), 42) + setitem_with_hash(d, i+.6, compute_hash(i+.6), -612) + return d[i+.5] + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + +def test_getitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + return getitem_with_hash(d, i+.5, compute_hash(i+.5)) + + assert f(29) == 42 + res = interpret(f, [27]) + assert res == 42 + +def test_delitem_with_hash(): + def f(i): + d = {i+.5: 42, i+.6: -612} + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + try: + delitem_with_hash(d, i+.5, compute_hash(i+.5)) + except KeyError: + pass + else: + raise AssertionError + return 0 + + f(29) + interpret(f, [27]) + +def test_rdict_with_hash(): + def f(i): + d = r_dict(strange_key_eq, strange_key_hash) + h = strange_key_hash("abc") + assert h == strange_key_hash("aXX") and strange_key_eq("abc", "aXX") + setitem_with_hash(d, "abc", h, i) + assert getitem_with_hash(d, "aXX", h) == i + try: + getitem_with_hash(d, "bYY", strange_key_hash("bYY")) + except KeyError: + pass + else: + raise AssertionError + return 0 + + assert f(29) == 0 + interpret(f, [27]) + def test_import_from_mixin(): class M: # old-style def f(self): pass diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -335,6 +335,14 @@ hop.exception_cannot_occur() return DictIteratorRepr(self, "items").newiter(hop) + def rtype_method_iterkeys_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "keys_with_hash").newiter(hop) + + def rtype_method_iteritems_with_hash(self, hop): + hop.exception_cannot_occur() + return DictIteratorRepr(self, "items_with_hash").newiter(hop) + def rtype_method_clear(self, hop): v_dict, = hop.inputargs(self) hop.exception_cannot_occur() @@ -358,6 +366,41 @@ v_res = hop.gendirectcall(target, *v_args) return self.recast_value(hop.llops, v_res) + def rtype_method_contains_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs(self, self.key_repr, + lltype.Signed) + hop.exception_is_here() + return hop.gendirectcall(ll_dict_contains_with_hash, + v_dict, v_key, v_hash) + + def rtype_method_setitem_with_hash(self, hop): + v_dict, v_key, v_hash, v_value = hop.inputargs( + self, self.key_repr, lltype.Signed, self.value_repr) + if self.custom_eq_hash: + hop.exception_is_here() + else: + hop.exception_cannot_occur() + hop.gendirectcall(ll_dict_setitem_with_hash, + v_dict, v_key, v_hash, v_value) + + def rtype_method_getitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + v_res = hop.gendirectcall(ll_dict_getitem_with_hash, + v_dict, v_key, v_hash) + return self.recast_value(hop.llops, v_res) + + def rtype_method_delitem_with_hash(self, hop): + v_dict, v_key, v_hash = hop.inputargs( + self, self.key_repr, lltype.Signed) + if not self.custom_eq_hash: + hop.has_implicit_exception(KeyError) # record that we know about it + hop.exception_is_here() + hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash) + class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)): def rtype_getitem((r_dict, r_key), hop): @@ -373,7 +416,7 @@ if not r_dict.custom_eq_hash: hop.has_implicit_exception(KeyError) # record that we know about it hop.exception_is_here() - return hop.gendirectcall(ll_dict_delitem, v_dict, v_key) + hop.gendirectcall(ll_dict_delitem, v_dict, v_key) def rtype_setitem((r_dict, r_key), hop): v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr) @@ -541,16 +584,21 @@ return bool(d) and d.num_live_items != 0 def ll_dict_getitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) + return ll_dict_getitem_with_hash(d, key, d.keyhash(key)) + +def ll_dict_getitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_LOOKUP) if index >= 0: return d.entries[index].value else: raise KeyError def ll_dict_setitem(d, key, value): - hash = d.keyhash(key) + ll_dict_setitem_with_hash(d, key, d.keyhash(key), value) + +def ll_dict_setitem_with_hash(d, key, hash, value): index = d.lookup_function(d, key, hash, FLAG_STORE) - return _ll_dict_setitem_lookup_done(d, key, value, hash, index) + _ll_dict_setitem_lookup_done(d, key, value, hash, index) # It may be safe to look inside always, it has a few branches though, and their # frequencies needs to be investigated. @@ -731,7 +779,10 @@ def ll_dict_delitem(d, key): - index = d.lookup_function(d, key, d.keyhash(key), FLAG_DELETE) + ll_dict_delitem_with_hash(d, key, d.keyhash(key)) + +def ll_dict_delitem_with_hash(d, key, hash): + index = d.lookup_function(d, key, hash, FLAG_DELETE) if index < 0: raise KeyError _ll_dict_del(d, index) @@ -1214,7 +1265,10 @@ ll_dict_items = _make_ll_keys_values_items('items') def ll_dict_contains(d, key): - i = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP) + return ll_dict_contains_with_hash(d, key, d.keyhash(key)) + +def ll_dict_contains_with_hash(d, key, hash): + i = d.lookup_function(d, key, hash, FLAG_LOOKUP) return i >= 0 def _ll_getnextitem(dic): diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py --- a/rpython/rtyper/rdict.py +++ b/rpython/rtyper/rdict.py @@ -72,20 +72,14 @@ return hop.gendirectcall(self.ll_dictiter, citerptr, v_dict) def rtype_next(self, hop): - variant = self.variant v_iter, = hop.inputargs(self) # record that we know about these two possible exceptions hop.has_implicit_exception(StopIteration) hop.has_implicit_exception(RuntimeError) hop.exception_is_here() v_index = hop.gendirectcall(self._ll_dictnext, v_iter) - if variant == 'items' and hop.r_result.lowleveltype != lltype.Void: - # this allocates the tuple for the result, directly in the function - # where it will be used (likely). This will let it be removed. - c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) - cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) - v_result = hop.genop('malloc', [c1, cflags], - resulttype = hop.r_result.lowleveltype) + # + # read 'iter.dict.entries' DICT = self.lowleveltype.TO.dict c_dict = hop.inputconst(lltype.Void, 'dict') v_dict = hop.genop('getfield', [v_iter, c_dict], resulttype=DICT) @@ -93,32 +87,61 @@ c_entries = hop.inputconst(lltype.Void, 'entries') v_entries = hop.genop('getfield', [v_dict, c_entries], resulttype=ENTRIES) - if variant != 'values': - KEY = ENTRIES.TO.OF.key - c_key = hop.inputconst(lltype.Void, 'key') - v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], - resulttype=KEY) - if variant != 'keys' and variant != 'reversed': - VALUE = ENTRIES.TO.OF.value - c_value = hop.inputconst(lltype.Void, 'value') - v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], - resulttype=VALUE) - if variant == 'keys' or variant == 'reversed': - return self.r_dict.recast_key(hop.llops, v_key) - elif variant == 'values': - return self.r_dict.recast_value(hop.llops, v_value) - elif hop.r_result.lowleveltype == lltype.Void: + # call the correct variant_*() method + method = getattr(self, 'variant_' + self.variant) + return method(hop, ENTRIES, v_entries, v_index) + + def get_tuple_result(self, hop, items_v): + # this allocates the tuple for the result, directly in the function + # where it will be used (likely). This will let it be removed. + if hop.r_result.lowleveltype is lltype.Void: return hop.inputconst(lltype.Void, None) - else: - assert variant == 'items' - ITEM0 = v_result.concretetype.TO.item0 - ITEM1 = v_result.concretetype.TO.item1 - if ITEM0 != v_key.concretetype: - v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0) - if ITEM1 != v_value.concretetype: - v_value = hop.genop('cast_pointer', [v_value], resulttype=ITEM1) - c_item0 = hop.inputconst(lltype.Void, 'item0') - c_item1 = hop.inputconst(lltype.Void, 'item1') - hop.genop('setfield', [v_result, c_item0, v_key]) - hop.genop('setfield', [v_result, c_item1, v_value]) - return v_result + c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO) + cflags = hop.inputconst(lltype.Void, {'flavor': 'gc'}) + v_result = hop.genop('malloc', [c1, cflags], + resulttype = hop.r_result.lowleveltype) + for i, v_item in enumerate(items_v): + ITEM = getattr(v_result.concretetype.TO, 'item%d' % i) + if ITEM != v_item.concretetype: + assert isinstance(ITEM, lltype.Ptr) + v_item = hop.genop('cast_pointer', [v_item], resulttype=ITEM) + c_item = hop.inputconst(lltype.Void, 'item%d' % i) + hop.genop('setfield', [v_result, c_item, v_item]) + return v_result + + def variant_keys(self, hop, ENTRIES, v_entries, v_index): + KEY = ENTRIES.TO.OF.key + c_key = hop.inputconst(lltype.Void, 'key') + v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key], + resulttype=KEY) + return self.r_dict.recast_key(hop.llops, v_key) + + variant_reversed = variant_keys + + def variant_values(self, hop, ENTRIES, v_entries, v_index): + VALUE = ENTRIES.TO.OF.value + c_value = hop.inputconst(lltype.Void, 'value') + v_value = hop.genop('getinteriorfield', [v_entries,v_index,c_value], + resulttype=VALUE) + return self.r_dict.recast_value(hop.llops, v_value) + + def variant_items(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value)) + + def variant_hashes(self, hop, ENTRIES, v_entries, v_index): + # there is not really a variant 'hashes', but this method is + # convenient for the following variants + return hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index) + + def variant_keys_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_hash)) + + def variant_items_with_hash(self, hop, ENTRIES, v_entries, v_index): + v_key = self.variant_keys(hop, ENTRIES, v_entries, v_index) + v_value = self.variant_values(hop, ENTRIES, v_entries, v_index) + v_hash = self.variant_hashes(hop, ENTRIES, v_entries, v_index) + return self.get_tuple_result(hop, (v_key, v_value, v_hash)) From noreply at buildbot.pypy.org Tue Sep 1 19:20:29 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 19:20:29 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: Accept a 2nd argument, which is the number of conflict entries to report Message-ID: <20150901172029.B69E61C0359@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: stmgc-c8-gcc Changeset: r79360:6521053a52f2 Date: 2015-09-01 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/6521053a52f2/ Log: Accept a 2nd argument, which is the number of conflict entries to report diff --git a/pypy/stm/print_stm_log.py b/pypy/stm/print_stm_log.py --- a/pypy/stm/print_stm_log.py +++ b/pypy/stm/print_stm_log.py @@ -301,7 +301,7 @@ stmlog.threads = threads stmlog.conflicts = conflicts -def dump_summary(stmlog): +def dump_summary(stmlog, maxcount=15): start_time = stmlog.start_time total_time = stmlog.total_time print @@ -330,7 +330,7 @@ print # values = stmlog.get_conflicts() - for c in values[:15]: + for c in values[:maxcount]: intervals = 60 timeline = [0] * intervals for t in c.timestamps: @@ -375,13 +375,17 @@ total += c.num_events return total - def dump(self): - dump_summary(self) + def dump(self, maxcount=15): + dump_summary(self, maxcount) def main(argv): - assert len(argv) == 1, "expected a filename argument" - StmLog(argv[0]).dump() + assert len(argv) >= 1, "expected a filename argument" + if len(argv) > 1: + maxcount = int(argv[1]) + else: + maxcount = 5 + StmLog(argv[0]).dump(maxcount) return 0 if __name__ == '__main__': From noreply at buildbot.pypy.org Tue Sep 1 19:23:30 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 19:23:30 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: This write_fence() was really needed, I think Message-ID: <20150901172330.8925E1C0359@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: use-gcc Changeset: r1951:bba995bf44bc Date: 2015-09-01 18:10 +0200 http://bitbucket.org/pypy/stmgc/changeset/bba995bf44bc/ Log: This write_fence() was really needed, I think diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -326,6 +326,12 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; + /* make sure .object is NULL in all segments before + "publishing" the entry in the hashtable. In other words, + the following write_fence() prevents a partially + initialized 'entry' from showing up in table->items[i], + where it could be read from other threads. */ + write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ From noreply at buildbot.pypy.org Tue Sep 1 19:24:32 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 19:24:32 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: threadlocalproperty: add the clear() method, to clear the value Message-ID: <20150901172432.7BE801C0359@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: stmgc-c8-gcc Changeset: r79361:81b0687acb77 Date: 2015-09-01 18:11 +0200 http://bitbucket.org/pypy/pypy/changeset/81b0687acb77/ Log: threadlocalproperty: add the clear() method, to clear the value in all threads. Bit of a hack. diff --git a/lib_pypy/transaction.py b/lib_pypy/transaction.py --- a/lib_pypy/transaction.py +++ b/lib_pypy/transaction.py @@ -239,12 +239,21 @@ def __init__(self, default_factory=None): self.tl_default_factory = default_factory self.tl_local = thread._local() + self.tl_all_threads = [] + + def clear(self, obj): + for wrefs in self.tl_all_threads: + try: + del wrefs[obj] + except KeyError: + pass def tl_wrefs(self): try: return self.tl_local.wrefs except AttributeError: self.tl_local.wrefs = wrefs = weakkeyiddict() + self.tl_all_threads.append(wrefs) return wrefs def __get__(self, obj, cls=None): From noreply at buildbot.pypy.org Tue Sep 1 19:24:34 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 1 Sep 2015 19:24:34 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: import stmgc/bba995bf44bc Message-ID: <20150901172434.B5E191C0359@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: stmgc-c8-gcc Changeset: r79362:5da67ac26dce Date: 2015-09-01 18:11 +0200 http://bitbucket.org/pypy/pypy/changeset/5da67ac26dce/ Log: import stmgc/bba995bf44bc diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -58f9e6d56296 +bba995bf44bc diff --git a/rpython/translator/stm/src_stm/stm/hashtable.c b/rpython/translator/stm/src_stm/stm/hashtable.c --- a/rpython/translator/stm/src_stm/stm/hashtable.c +++ b/rpython/translator/stm/src_stm/stm/hashtable.c @@ -326,6 +326,12 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; + /* make sure .object is NULL in all segments before + "publishing" the entry in the hashtable. In other words, + the following write_fence() prevents a partially + initialized 'entry' from showing up in table->items[i], + where it could be read from other threads. */ + write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ From noreply at buildbot.pypy.org Tue Sep 1 21:14:31 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 21:14:31 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: we don't need to force short preamble just by doing setfield Message-ID: <20150901191431.155DF1C0359@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79363:b36276bbef65 Date: 2015-09-01 20:30 +0200 http://bitbucket.org/pypy/pypy/changeset/b36276bbef65/ Log: we don't need to force short preamble just by doing setfield diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -76,7 +76,7 @@ if self.possible_aliasing(optheap, structinfo): self.force_lazy_setfield(optheap, op.getdescr()) assert not self.possible_aliasing(optheap, structinfo) - cached_field = self._getfield(structinfo, op.getdescr(), optheap) + cached_field = self._getfield(structinfo, op.getdescr(), optheap, False) if cached_field is not None: cached_field = optheap.get_box_replacement(cached_field) @@ -118,9 +118,11 @@ def _getvalue(self, op): return op.getarg(1) - def _getfield(self, opinfo, descr, optheap): + def _getfield(self, opinfo, descr, optheap, true_force=True): res = opinfo.getfield(descr, optheap) if isinstance(res, PreambleOp): + if not true_force: + return res.op res = optheap.optimizer.force_op_from_preamble(res) opinfo.setfield(descr, None, res, optheap) return res @@ -163,9 +165,11 @@ def _getvalue(self, op): return op.getarg(2) - def _getfield(self, opinfo, descr, optheap): + def _getfield(self, opinfo, descr, optheap, true_force=True): res = opinfo.getitem(descr, self.index, optheap) if isinstance(res, PreambleOp): + if not true_force: + return res.op index = res.preamble_op.getarg(1).getint() res = optheap.optimizer.force_op_from_preamble(res) opinfo.setitem(descr, index, None, res, optheap=optheap) From noreply at buildbot.pypy.org Tue Sep 1 21:14:33 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 21:14:33 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: hack sliiightly differently Message-ID: <20150901191433.89A861C0359@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79364:587467d78277 Date: 2015-09-01 21:14 +0200 http://bitbucket.org/pypy/pypy/changeset/587467d78277/ Log: hack sliiightly differently diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -100,6 +100,9 @@ # need any _lazy_setfield: the heap value is already right. # Note that this may reset to None a non-None lazy_setfield, # cancelling its previous effects with no side effect. + + # Now, we have to force the item in the short preamble + self._getfield(structinfo, op.getdescr(), optheap) self._lazy_setfield = None def getfield_from_cache(self, optheap, opinfo, 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 @@ -30,7 +30,7 @@ op = self.lst[i] if op is None: break - if opt.get_box_replacement(op.getarg(0)).same_box(box0) and op.getdescr() is descr: + if box0.same_box(opt.get_box_replacement(op.getarg(0))) and op.getdescr() is descr: op = self.force_preamble_op(opt, op, i) return opt.get_box_replacement(op) return None @@ -40,8 +40,9 @@ op = self.lst[i] if op is None: break - if (opt.get_box_replacement(op.getarg(0)).same_box(box0) and opt.get_box_replacement(op.getarg(1)).same_box(box1) - and op.getdescr() is descr): + if (box0.same_box(opt.get_box_replacement(op.getarg(0))) and + box1.same_box(opt.get_box_replacement(op.getarg(1))) and + op.getdescr() is descr): op = self.force_preamble_op(opt, op, i) return opt.get_box_replacement(op) return None diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -99,7 +99,11 @@ optpure = opt.optimizer.optpure if optpure is None: return - op = self.res + if invented_name: + op = self.orig_op.copy_and_change(self.orig_op.getopnum()) + op.set_forwarded(self.res) + else: + op = self.res if preamble_op.is_call(): optpure.extra_call_pure.append(PreambleOp(op, preamble_op, invented_name)) @@ -199,8 +203,7 @@ return ProducedShortOp(self, self.preamble_op) def produce_op(self, opt, preamble_op, exported_infos, invented_name): - pass - #assert not invented_name + assert not invented_name def __repr__(self): return "INP(%r -> %r)" % (self.res, self.preamble_op) @@ -233,8 +236,7 @@ self.add_op_to_short(shortop) # for op, produced_op in self.produced_short_boxes.iteritems(): - if not isinstance(produced_op, ShortInputArg): - short_boxes.append(produced_op) + short_boxes.append(produced_op) for short_op in self.const_short_boxes: getfield_op = short_op.getfield_op @@ -262,13 +264,13 @@ else: return None - def _pick_op_index(self, lst, pick_inparg=True): + def _pick_op_index(self, lst, pick_other=True): index = -1 for i, item in enumerate(lst): if (not isinstance(item.short_op, HeapOp) and - (pick_inparg or not isinstance(item.short_op, ShortInputArg))): + (pick_other or isinstance(item.short_op, ShortInputArg))): if index != -1: - assert pick_inparg + assert pick_other return self._pick_op_index(lst, False) index = i if index == -1: @@ -293,7 +295,9 @@ opnum = OpHelpers.same_as_for_type(shortop.res.type) new_name = ResOperation(opnum, [shortop.res]) assert lst[i].short_op is not pop.short_op + orig_op = lst[i].short_op.res lst[i].short_op.res = new_name + lst[i].short_op.orig_op = orig_op lst[i].invented_name = True self.produced_short_boxes[new_name] = lst[i] else: @@ -389,9 +393,6 @@ info = empty_info preamble_op.set_forwarded(info) self.short = [] - self.label_dict = {} - for arg in label_args: - self.label_dict[arg] = None self.used_boxes = [] self.short_preamble_jump = [] self.extra_same_as = [] @@ -401,12 +402,9 @@ """ Notice that we're actually using the preamble_op, add it to label and jump """ + op = preamble_op.op.get_box_replacement() if preamble_op.invented_name: - self.extra_same_as.append(preamble_op.op) - op = preamble_op.op - if op in self.label_dict: - return - self.label_dict[op] = None + self.extra_same_as.append(op) self.used_boxes.append(op) self.short_preamble_jump.append(preamble_op.preamble_op) @@ -434,12 +432,12 @@ self.label_args = label_args def add_preamble_op(self, preamble_op): + """ Notice that we're actually using the preamble_op, add it to + label and jump + """ + op = preamble_op.op.get_box_replacement() if preamble_op.invented_name: - self.extra_same_as.append(preamble_op.op) - op = preamble_op.op - if op in self.sb.label_dict: - return - self.sb.label_dict[op] = None + self.extra_same_as.append(op) self.label_args.append(op) self.jump_args.append(preamble_op.preamble_op) 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 @@ -2400,16 +2400,15 @@ guard_true(i3) [] i4 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - #i7 = same_as(i2) # This same_as should be killed by backend - #i6 = same_as(i4) - jump(p1, i1, i2, i4) #, i6) - """ - expected = """ - [p1, i1, i2, i4] #, i5] + i6 = same_as_i(i4) + jump(p1, i1, i2, i4, i6) + """ + expected = """ + [p1, i1, i2, i4, i5] setfield_gc(p1, i1, descr=valuedescr) guard_true(i4) [] setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, 1) # , i5) + jump(p1, i1, i2, i5, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2432,16 +2431,15 @@ i4 = int_neg(i2) setfield_gc(p1, NULL, descr=nextdescr) escape_n() - #i5 = same_as(i4) - jump(p1, i2, i4) - """ - expected = """ - [p1, i2, i4] # i5 + i5 = same_as_i(i4) + jump(p1, i2, i4, i5) + """ + expected = """ + [p1, i2, i4, i5] guard_true(i4) [p1] setfield_gc(p1, NULL, descr=nextdescr) escape_n() - jump(p1, i2, 1) - #jump(p1, i2, i5, i5) + jump(p1, i2, i5, i5) """ self.optimize_loop(ops, expected, preamble) @@ -2467,11 +2465,11 @@ jump(p1, i2, i4) #, i5) """ expected = """ - [p1, i2, i4] #, i5] + [p1, i2, i4, i5] guard_true(i4) [i2, p1] setfield_gc(p1, NULL, descr=nextdescr) escape_n() - jump(p1, i2, 1) #, i5) + jump(p1, i2, i5, i5) """ self.optimize_loop(ops, expected) @@ -2494,17 +2492,16 @@ guard_true(i5) [] i4 = int_neg(i2) setfield_gc(p1, i2, descr=valuedescr) - #i8 = same_as(i2) # This same_as should be killed by backend - #i7 = same_as(i4) - jump(p1, i1, i2, i4) #, i7) - """ - expected = """ - [p1, i1, i2, i4] #, i7] + i7 = same_as_i(i4) + jump(p1, i1, i2, i4, i7) + """ + expected = """ + [p1, i1, i2, i4, i7] setfield_gc(p1, i1, descr=valuedescr) i5 = int_eq(i4, 5) guard_true(i5) [] setfield_gc(p1, i2, descr=valuedescr) - jump(p1, i1, i2, 5) # , i7) + jump(p1, i1, i2, i7, i7) """ self.optimize_loop(ops, expected, preamble) @@ -2723,16 +2720,16 @@ p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - #i101 = same_as(i4) - jump(p1, i2, i4, p4) #, i101) - """ - expected = """ - [p1, i2, i4, p4] #, i5] + i101 = same_as_i(i4) + jump(p1, i2, i4, p4, i101) + """ + expected = """ + [p1, i2, i4, p4, i5] guard_true(i4) [p1, p4] p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p4, descr=nextdescr) setfield_gc(p1, p2, descr=nextdescr) - jump(p1, i2, 1, p4) #, i5) + jump(p1, i2, i5, p4, i5) """ self.optimize_loop(ops, expected, preamble) @@ -3697,16 +3694,17 @@ jump(p1, i4, i3) ''' expected = ''' - [p1, i4, i3] - setfield_gc(p1, i3, descr=valuedescr) - jump(p1, i3, i3) + [p1, i4, i3, i5] + setfield_gc(p1, i5, descr=valuedescr) + jump(p1, i3, i5, i5) ''' preamble = ''' [p1, i1, i4] setfield_gc(p1, i1, descr=valuedescr) i3 = call_i(p1, descr=elidablecalldescr) setfield_gc(p1, i3, descr=valuedescr) - jump(p1, i4, i3) + ifoo = same_as_i(i3) + jump(p1, i4, i3, ifoo) ''' self.optimize_loop(ops, expected, preamble) @@ -3723,9 +3721,9 @@ jump(p1, i4, i3) ''' expected = ''' - [p1, i4, i3] - setfield_gc(p1, i3, descr=valuedescr) - jump(p1, i3, i3) + [p1, i4, i3, i5] + setfield_gc(p1, i5, descr=valuedescr) + jump(p1, i3, i5, i5) ''' preamble = ''' [p1, i1, i4] @@ -3733,9 +3731,8 @@ i3 = call_i(p1, descr=elidable2calldescr) guard_no_exception() [] setfield_gc(p1, i3, descr=valuedescr) - #i148 = same_as(i3) - #i147 = same_as(i3) - jump(p1, i4, i3) #, i148) + i147 = same_as_i(i3) + jump(p1, i4, i3, i147) ''' self.optimize_loop(ops, expected, preamble) @@ -3781,16 +3778,16 @@ jump(p1, i4, i3) ''' expected = ''' - [p1, i4, i3] + [p1, i4, i3, i5] setfield_gc(p1, i4, descr=valuedescr) - jump(p1, i3, i3) + jump(p1, i3, i5, i5) ''' preamble = ''' [p1, i1, i4] setfield_gc(p1, i1, descr=valuedescr) i3 = call_i(p1, descr=elidablecalldescr) - # i151 = same_as_i(i3) - jump(p1, i4, i3) + i151 = same_as_i(i3) + jump(p1, i4, i3, i151) ''' self.optimize_loop(ops, expected, preamble) @@ -3810,14 +3807,14 @@ escape_n(i1) escape_n(i2) i4 = call_i(123456, 4, i0, 6, descr=elidablecalldescr) - # i153 = same_as_i(i4) - jump(i0, i4) + i153 = same_as_i(i4) + jump(i0, i4, i153) ''' expected = ''' - [i0, i4] + [i0, i4, i5] escape_n(42) escape_n(i4) - jump(i0, i4) + jump(i0, i5, i5) ''' self.optimize_loop(ops, expected, preamble, call_pure_results) @@ -3834,12 +3831,13 @@ escape_n(i0) i3 = call_i(123456, p0, descr=elidable2calldescr) guard_no_exception() [] - jump(p0, i3) + ifoo = same_as_i(i3) + jump(p0, i3, ifoo) ''' expected = ''' - [p0, i3] + [p0, i3, ifoo] escape_n(i3) - jump(p0, i3) + jump(p0, ifoo, ifoo) ''' self.optimize_loop(ops, expected, preamble) @@ -4686,7 +4684,6 @@ [i0, p0] p1 = new_array(i0, descr=gcarraydescr) i1 = arraylen_gc(p1) - ifoo = arraylen_gc(p0, descr=gcarraydescr) setarrayitem_gc(p0, 0, p1, descr=gcarraydescr) jump(i0, p0) """ @@ -6421,12 +6418,13 @@ [p1, i1, i2, i3] escape_n(i3) i4 = int_sub(i2, i1) - jump(p1, i1, i2, i4) - """ - expected = """ - [p1, i1, i2, i3] + i5 = same_as_i(i4) + jump(p1, i1, i2, i4, i5) + """ + expected = """ + [p1, i1, i2, i3, i5] escape_n(i3) - jump(p1, i1, i2, i3) + jump(p1, i1, i2, i5, i5) """ self.optimize_strunicode_loop(ops, expected, preamble) @@ -8156,9 +8154,9 @@ jump(i1, i3) """ expected = """ - [i1, i2, i3] + [i1, i2, i3, i4] call_n(i3, descr=nonwritedescr) - jump(i1, i2, i3) + jump(i1, i2, i3, i4) """ short = """ [i1, i2] @@ -8166,7 +8164,7 @@ i4 = int_add(i3, i3) i5 = int_add(i4, i4) i6 = int_add(i5, i5) - jump(i6) + jump(i6, i3) """ self.optimize_loop(ops, expected, expected_short=short) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -21,8 +21,10 @@ self.optunroll.short_preamble_producer.use_box(op, preamble_op.preamble_op, self) if not preamble_op.op.is_constant(): + if preamble_op.invented_name: + op = self.get_box_replacement(op) self.optunroll.potential_extra_ops[op] = preamble_op - return op + return preamble_op.op return preamble_op def setinfo_from_preamble_list(self, lst, infos): diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -80,6 +80,11 @@ def getopnum(self): return self.opnum + #def same_box(self, other): + # if self.is_same_as(): + # return self is other or self.getarg(0).same_box(other) + # return self is other + def get_forwarded(self): return self._forwarded From noreply at buildbot.pypy.org Tue Sep 1 21:15:33 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 21:15:33 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: commit that excpetion Message-ID: <20150901191533.76DA31C0359@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79365:1114aa7d7743 Date: 2015-09-01 21:15 +0200 http://bitbucket.org/pypy/pypy/changeset/1114aa7d7743/ Log: commit that excpetion diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -339,6 +339,7 @@ loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: + raise Exception("think about it") xxx # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], From noreply at buildbot.pypy.org Tue Sep 1 23:11:31 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 23:11:31 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix virtual_ref optimization Message-ID: <20150901211131.AA3C81C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79366:04e67e43db5a Date: 2015-09-01 23:11 +0200 http://bitbucket.org/pypy/pypy/changeset/04e67e43db5a/ Log: fix virtual_ref optimization diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -160,10 +160,11 @@ return False tokeninfo = self.getptrinfo(tokenop) if (tokeninfo is not None and tokeninfo.is_constant() and - not tokeninfo.is_null()): - forcedvalue = vref.getfield(vrefinfo.descr_forced, None) - if forcedvalue is not None and not forcedvalue.is_null(): - self.make_equal_to(op, forcedvalue) + not tokeninfo.is_nonnull()): + forcedop = vref.getfield(vrefinfo.descr_forced, None) + forcedinfo = self.getptrinfo(forcedop) + if forcedinfo is not None and not forcedinfo.is_null(): + self.make_equal_to(op, forcedop) self.last_emitted_operation = REMOVED return True return False From noreply at buildbot.pypy.org Tue Sep 1 23:16:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 1 Sep 2015 23:16:14 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: safe against situation where no item was ever read or written Message-ID: <20150901211614.82AD21C08B9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79367:a4b4f897457f Date: 2015-09-01 23:15 +0200 http://bitbucket.org/pypy/pypy/changeset/a4b4f897457f/ Log: safe against situation where no item was ever read or written 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 @@ -220,6 +220,8 @@ def produce_short_preamble_ops(self, structbox, descr, index, optimizer, shortboxes): + if self._fields is None: + return op = optimizer.get_box_replacement(self._fields[descr.get_index()]) opnum = OpHelpers.getfield_for_descr(descr) getfield_op = ResOperation(opnum, [structbox], descr=descr) @@ -492,6 +494,8 @@ def produce_short_preamble_ops(self, structbox, descr, index, optimizer, shortboxes): + if self._items is None: + return item = self._items[index] if item is not None: op = optimizer.get_box_replacement(item) From noreply at buildbot.pypy.org Wed Sep 2 11:39:03 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 2 Sep 2015 11:39:03 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: a fix to force the right virtual state if we have one, maybe we can simplify jump_to_existing trace just by passing one Message-ID: <20150902093903.1A4111C15C8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79368:ededaf3d4b4d Date: 2015-09-02 11:38 +0200 http://bitbucket.org/pypy/pypy/changeset/ededaf3d4b4d/ Log: a fix to force the right virtual state if we have one, maybe we can simplify jump_to_existing trace just by passing one diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -562,7 +562,7 @@ frame_depth = max(self.current_clt.frame_info.jfi_frame_depth, frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE) if logger: - logger.log_bridge(inputargs, operations, "rewritten", + logger.log_bridge(inputargs, operations, "rewritten", faildescr, ops_offset=ops_offset) self.fixup_target_tokens(rawstart) self.update_frame_depth(frame_depth) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -3,6 +3,7 @@ from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes,\ ShortPreambleBuilder, ExtendedShortPreambleBuilder, PreambleOp from rpython.jit.metainterp.optimizeopt import info, intutils +from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer,\ Optimization, LoopInfo, MININT, MAXINT from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo @@ -122,7 +123,18 @@ start_label.getarglist()[:], ops, call_pure_results, False, flush=False) label_op = ResOperation(rop.LABEL, label_args, start_label.getdescr()) - args = state.virtual_state.make_inputargs( + for a in end_jump.getarglist(): + self.optimizer.force_box_for_end_of_preamble( + self.optimizer.get_box_replacement(a)) + current_vs = self.get_virtual_state(end_jump.getarglist()) + # pick the vs we want to jump to + celltoken = start_label.getdescr() + assert isinstance(celltoken, JitCellToken) + target_virtual_state = self.pick_virtual_state(current_vs, + state.virtual_state, + celltoken.target_tokens) + # force the boxes for virtual state to match + args = target_virtual_state.make_inputargs( [self.get_box_replacement(x) for x in end_jump.getarglist()], self.optimizer, force_boxes=True) for arg in args: @@ -131,11 +143,8 @@ target_token = self.finalize_short_preamble(label_op, state.virtual_state) label_op.setdescr(target_token) - # force the boxes for virtual state to match new_virtual_state = self.jump_to_existing_trace(end_jump, label_op) if new_virtual_state is not None: - celltoken = start_label.getdescr() - assert isinstance(celltoken, JitCellToken) self.jump_to_preamble(celltoken, end_jump, info) return (UnrollInfo(target_token, label_op, [], self.optimizer.quasi_immutable_deps), @@ -144,6 +153,16 @@ self.optimizer.quasi_immutable_deps), self.optimizer._newoperations) + def pick_virtual_state(self, my_vs, label_vs, target_tokens): + if target_tokens is None: + return label_vs # for tests + for token in target_tokens: + if token.virtual_state is None: + continue + if token.virtual_state.generalization_of(my_vs, self.optimizer): + return token.virtual_state + return label_vs + def optimize_bridge(self, start_label, operations, call_pure_results, inline_short_preamble): self._check_no_forwarding([start_label.getarglist(), diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -145,10 +145,12 @@ assert isinstance(other, AbstractVirtualStructStateInfo) assert len(self.fielddescrs) == len(self.fieldstate) assert len(other.fielddescrs) == len(other.fieldstate) - opinfo = state.optimizer.getptrinfo(box) if runtime_box is not None: + opinfo = state.optimizer.getptrinfo(box) assert opinfo.is_virtual() - assert isinstance(opinfo, AbstractStructPtrInfo) + assert isinstance(opinfo, AbstractStructPtrInfo) + else: + opinfo = None if len(self.fielddescrs) != len(other.fielddescrs): raise VirtualStatesCantMatch("field descrs don't match") @@ -551,8 +553,8 @@ if s: s.enum(self) - def generalization_of(self, other, bad=None, cpu=None): - state = GenerateGuardState(cpu=cpu, bad=bad) + def generalization_of(self, other, optimizer): + state = GenerateGuardState(optimizer) assert len(self.state) == len(other.state) try: for i in range(len(self.state)): diff --git a/rpython/jit/metainterp/test/test_virtual.py b/rpython/jit/metainterp/test/test_virtual.py --- a/rpython/jit/metainterp/test/test_virtual.py +++ b/rpython/jit/metainterp/test/test_virtual.py @@ -214,7 +214,7 @@ assert res == f(20) self.check_trace_count(2) self.check_resops(**{self._new_op: 1}) - self.check_resops(int_mul=0, call=1) + self.check_resops(int_mul=0, call_i=1) def test_two_virtuals(self): myjitdriver = JitDriver(greens=[], reds=['n', 'prev']) From noreply at buildbot.pypy.org Wed Sep 2 11:46:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 2 Sep 2015 11:46:17 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: an awkward translation workaround Message-ID: <20150902094617.2E2AF1C0726@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79369:a50415baecc8 Date: 2015-09-02 11:46 +0200 http://bitbucket.org/pypy/pypy/changeset/a50415baecc8/ Log: an awkward translation workaround diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -158,7 +158,7 @@ for i in range(len(self.fielddescrs)): if other.fielddescrs[i] is not self.fielddescrs[i]: raise VirtualStatesCantMatch("field descrs don't match") - if runtime_box is not None: + if runtime_box is not None and opinfo is not None: fieldbox = opinfo._fields[self.fielddescrs[i].get_index()] # must be there fieldbox_runtime = state.get_runtime_field(runtime_box, From noreply at buildbot.pypy.org Wed Sep 2 13:09:41 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 2 Sep 2015 13:09:41 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix fix ifx Message-ID: <20150902110941.85AB31C0362@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79370:03db733f67cf Date: 2015-09-02 12:51 +0200 http://bitbucket.org/pypy/pypy/changeset/03db733f67cf/ Log: fix fix ifx diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -1,4 +1,5 @@ +import sys from rpython.jit.metainterp.history import Const, TargetToken, JitCellToken from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes,\ ShortPreambleBuilder, ExtendedShortPreambleBuilder, PreambleOp @@ -143,16 +144,37 @@ target_token = self.finalize_short_preamble(label_op, state.virtual_state) label_op.setdescr(target_token) - new_virtual_state = self.jump_to_existing_trace(end_jump, label_op) + try: + new_virtual_state = self.jump_to_existing_trace(end_jump, label_op) + except InvalidLoop: + # inlining short preamble failed, jump to preamble + self.jump_to_preamble(celltoken, end_jump, info) + return (UnrollInfo(target_token, label_op, [], + self.optimizer.quasi_immutable_deps), + self.optimizer._newoperations) if new_virtual_state is not None: self.jump_to_preamble(celltoken, end_jump, info) return (UnrollInfo(target_token, label_op, [], self.optimizer.quasi_immutable_deps), self.optimizer._newoperations) + + self.disable_retracing_if_max_retrace_guards( + self.optimizer._newoperations, target_token) + return (UnrollInfo(target_token, label_op, extra_same_as, self.optimizer.quasi_immutable_deps), self.optimizer._newoperations) + def disable_retracing_if_max_retrace_guards(self, ops, target_token): + maxguards = self.optimizer.metainterp_sd.warmrunnerdesc.memory_manager.max_retrace_guards + count = 0 + for op in ops: + if op.is_guard(): + count += 1 + if count > maxguards: + assert isinstance(target_token, TargetToken) + target_token.targeting_jitcell_token.retraced_count = sys.maxint + def pick_virtual_state(self, my_vs, label_vs, target_tokens): if target_tokens is None: return label_vs # for tests @@ -191,12 +213,6 @@ else: debug_print("Retrace count reached, jumping to preamble") return self.jump_to_preamble(cell_token, jump_op, info) - #maxguards = warmrunnerdescr.memory_manager.max_retrace_guards - #guard_count = self.count_guards(self.optimizer._newoperations) - #if guard_count > maxguards: - # target_token = cell_token.target_tokens[0] - # target_token.targeting_jitcell_token.retraced_count = sys.maxint - # return self.jump_to_preamble(cell_token, jump_op, info) exported_state = self.export_state(start_label, operations[-1].getarglist(), info.inputargs) @@ -370,13 +386,6 @@ return effectinfo.extraeffect != effectinfo.EF_ELIDABLE_CANNOT_RAISE return False - def count_guards(self, ops): - guard_count = 0 - for op in ops: - if op.is_guard(): - guard_count += 1 - return guard_count - class UnrollInfo(LoopInfo): """ A state after optimizing the peeled loop, contains the following: diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -294,15 +294,18 @@ raise VirtualStatesCantMatch("other is a different kind of array") fieldbox = None fieldbox_runtime = None - opinfo = state.optimizer.getptrinfo(box) - assert isinstance(opinfo, ArrayPtrInfo) + if box is not None: + opinfo = state.optimizer.getptrinfo(box) + assert isinstance(opinfo, ArrayPtrInfo) + else: + opinfo = None for i in range(self.length): for descr in self.fielddescrs: index = i * len(self.fielddescrs) + descr.get_index() fieldstate = self.fieldstate[index] if fieldstate is None: continue - if box is not None: + if box is not None and opinfo is not None: fieldbox = opinfo._items[index] fieldbox_runtime = state.get_runtime_interiorfield( runtime_box, descr, i) From noreply at buildbot.pypy.org Thu Sep 3 07:52:12 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 07:52:12 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Kill guard_nonnull_gc_type again Message-ID: <20150903055212.6FD521C05B6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79386:0ffbe45ebce5 Date: 2015-09-03 07:26 +0200 http://bitbucket.org/pypy/pypy/changeset/0ffbe45ebce5/ Log: Kill guard_nonnull_gc_type again 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 @@ -913,10 +913,6 @@ if TYPE != typeid.STRUCT_OR_ARRAY: self.fail_guard(descr) - def execute_guard_nonnull_gc_type(self, descr, arg, typeid): - self.execute_guard_nonnull(descr, arg) - self.execute_guard_gc_type(descr, arg, typeid) - def execute_guard_no_exception(self, descr): if self.last_exception is not None: self.fail_guard(descr) diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -4840,9 +4840,6 @@ c_typeid = ConstInt(descr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void') assert not self.guard_failed - self.execute_operation(rop.GUARD_NONNULL_GC_TYPE, [t_box, c_typeid], - 'void') - assert not self.guard_failed def test_passing_guard_gc_type_array(self): if not self.cpu.supports_guard_gc_type: @@ -4852,9 +4849,6 @@ c_typeid = ConstInt(arraydescr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void') assert not self.guard_failed - self.execute_operation(rop.GUARD_NONNULL_GC_TYPE, [a_box, c_typeid], - 'void') - assert not self.guard_failed def test_failing_guard_gc_type(self): if not self.cpu.supports_guard_gc_type: @@ -4866,17 +4860,10 @@ c_ttypeid = ConstInt(tdescr.get_type_id()) c_utypeid = ConstInt(udescr.get_type_id()) c_atypeid = ConstInt(adescr.get_type_id()) - null_box = self.null_instance() for opname, args in [(rop.GUARD_GC_TYPE, [t_box, c_utypeid]), (rop.GUARD_GC_TYPE, [u_box, c_ttypeid]), (rop.GUARD_GC_TYPE, [a_box, c_utypeid]), (rop.GUARD_GC_TYPE, [t_box, c_atypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [t_box, c_utypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [u_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [a_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [u_box, c_atypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [null_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [null_box, c_atypeid]), ]: assert self.execute_operation(opname, args, 'void') == None assert self.guard_failed diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1734,7 +1734,9 @@ self.mc.CMP(locs[0], locs[1]) self.implement_guard(guard_token, 'NE') - def _cmp_guard_class(self, loc_ptr, loc_classptr): + def _cmp_guard_class(self, locs): + loc_ptr = locs[0] + loc_classptr = locs[1] offset = self.cpu.vtable_offset if offset is not None: self.mc.CMP(mem(loc_ptr, offset), loc_classptr) @@ -1770,18 +1772,8 @@ assert isinstance(loc_expected_typeid, ImmedLoc) self.mc.CMP32_mi((loc_ptr.value, 0), loc_expected_typeid.value) - def _cmp_guard_class_or_gc_type(self, guard_op, locs): - if ( guard_op.getopnum() == rop.GUARD_CLASS or - guard_op.getopnum() == rop.GUARD_NONNULL_CLASS): - self._cmp_guard_class(locs[0], locs[1]) - elif (guard_op.getopnum() == rop.GUARD_GC_TYPE or - guard_op.getopnum() == rop.GUARD_NONNULL_GC_TYPE): - self._cmp_guard_gc_type(locs[0], locs[1]) - else: - assert 0 - def genop_guard_guard_class(self, ign_1, guard_op, guard_token, locs, ign_2): - self._cmp_guard_class_or_gc_type(guard_op, locs) + self._cmp_guard_class(locs) self.implement_guard(guard_token, 'NE') def genop_guard_guard_nonnull_class(self, ign_1, guard_op, @@ -1790,7 +1782,7 @@ # Patched below self.mc.J_il8(rx86.Conditions['B'], 0) jb_location = self.mc.get_relative_pos() - self._cmp_guard_class_or_gc_type(guard_op, locs) + self._cmp_guard_class(locs) # patch the JB above offset = self.mc.get_relative_pos() - jb_location assert 0 < offset <= 127 @@ -1798,8 +1790,10 @@ # self.implement_guard(guard_token, 'NE') - genop_guard_guard_gc_type = genop_guard_guard_class - genop_guard_guard_nonnull_gc_type = genop_guard_guard_nonnull_class + def genop_guard_guard_gc_type(self, ign_1, guard_op, + guard_token, locs, ign_2): + self._cmp_guard_gc_type(locs[0], locs[1]) + self.implement_guard(guard_token, 'NE') def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -429,7 +429,6 @@ consider_guard_nonnull_class = consider_guard_class consider_guard_gc_type = consider_guard_class - consider_guard_nonnull_gc_type = consider_guard_class def _consider_binop_part(self, op, symm=False): x = op.getarg(0) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -661,8 +661,9 @@ 'GUARD_NONNULL/1d/n', 'GUARD_ISNULL/1d/n', 'GUARD_NONNULL_CLASS/2d/n', - 'GUARD_GC_TYPE/2d/n', - 'GUARD_NONNULL_GC_TYPE/2d/n', + 'GUARD_GC_TYPE/2d/n', # only if supports_guard_gc_type + 'GUARD_IS_OBJECT/1d/n', # only if supports_guard_gc_type + 'GUARD_SUBCLASS/2d/n', # only if supports_guard_gc_type '_GUARD_FOLDABLE_LAST', 'GUARD_NO_EXCEPTION/0d/n', # may be called with an exception currently set 'GUARD_EXCEPTION/1d/r', # may be called with an exception currently set From noreply at buildbot.pypy.org Thu Sep 3 07:52:14 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 07:52:14 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: guard_is_object, guard_subclass in the llgraph backend Message-ID: <20150903055214.9935E1C05B6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79387:a714b41006ed Date: 2015-09-03 07:52 +0200 http://bitbucket.org/pypy/pypy/changeset/a714b41006ed/ Log: guard_is_object, guard_subclass in the llgraph backend 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 @@ -913,6 +913,26 @@ if TYPE != typeid.STRUCT_OR_ARRAY: self.fail_guard(descr) + def execute_guard_is_object(self, descr, arg): + TYPE = arg._obj.container._TYPE + while TYPE is not rclass.OBJECT: + if not isinstance(TYPE, lltype.GcStruct): # or TYPE is None + self.fail_guard(descr) + return + _, TYPE = TYPE._first_struct() + + def execute_guard_subclass(self, descr, arg, klass): + value = lltype.cast_opaque_ptr(rclass.OBJECTPTR, arg) + expected_class = llmemory.cast_adr_to_ptr( + llmemory.cast_int_to_adr(klass), + rclass.CLASSTYPE) + if (expected_class.subclassrange_min + <= value.typeptr.subclassrange_min + <= expected_class.subclassrange_max): + pass + else: + self.fail_guard(descr) + def execute_guard_no_exception(self, descr): if self.last_exception is not None: self.fail_guard(descr) diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -4867,3 +4867,71 @@ ]: assert self.execute_operation(opname, args, 'void') == None assert self.guard_failed + + def test_guard_is_object(self): + if not self.cpu.supports_guard_gc_type: + py.test.skip("guard_gc_type not available") + t_box, _, _ = self.alloc_instance(self.T) + self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void') + # + assert not self.guard_failed + a_box, _ = self.alloc_array_of(rffi.SHORT, 342) + self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void') + assert self.guard_failed + # + S = lltype.GcStruct('S') + s = lltype.malloc(S, immortal=True, zero=True) + s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s)) + self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void') + assert self.guard_failed + + def test_guard_subclass(self): + if not self.cpu.supports_guard_gc_type: + py.test.skip("guard_gc_type not available") + + xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + xtp.subclassrange_min = 1 + xtp.subclassrange_max = 3 + X = lltype.GcStruct('X', ('parent', rclass.OBJECT), + hints={'vtable': xtp._obj}) + xptr = lltype.malloc(X) + xptr.parent.typeptr = xtp + x_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, xptr)) + X_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(xtp))) + + ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + ytp.subclassrange_min = 2 + ytp.subclassrange_max = 2 + assert rclass.ll_issubclass(ytp, xtp) + Y = lltype.GcStruct('Y', ('parent', X), + hints={'vtable': ytp._obj}) + yptr = lltype.malloc(Y) + yptr.parent.parent.typeptr = ytp + y_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, yptr)) + Y_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ytp))) + + ztp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + ztp.subclassrange_min = 4 + ztp.subclassrange_max = 5 + assert not rclass.ll_issubclass(ztp, xtp) + assert not rclass.ll_issubclass(xtp, ztp) + Z = lltype.GcStruct('Z', ('parent', rclass.OBJECT), + hints={'vtable': ztp._obj}) + zptr = lltype.malloc(Z) + zptr.parent.typeptr = ztp + z_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, zptr)) + Z_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ztp))) + + for num, arg, klass, is_subclass in [ + (1, x_box, X_box, True), + (2, x_box, Y_box, False), + (3, x_box, Z_box, False), + (4, y_box, X_box, True), + (5, y_box, Y_box, True), + (6, y_box, Z_box, False), + (7, z_box, X_box, False), + (8, z_box, Y_box, False), + (9, z_box, Z_box, True), + ]: + self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void') + assert self.guard_failed == (not is_subclass) From noreply at buildbot.pypy.org Thu Sep 3 07:54:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 07:54:36 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Not implemented yet, make sure it crashes translation Message-ID: <20150903055436.56B4A1C05B6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79388:da32d2f36f60 Date: 2015-09-03 07:54 +0200 http://bitbucket.org/pypy/pypy/changeset/da32d2f36f60/ Log: Not implemented yet, make sure it crashes translation diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -430,6 +430,12 @@ consider_guard_nonnull_class = consider_guard_class consider_guard_gc_type = consider_guard_class + def consider_guard_is_object(self, op): + xxx + + def consider_guard_subclass(self, op): + xxx + def _consider_binop_part(self, op, symm=False): x = op.getarg(0) y = op.getarg(1) From noreply at buildbot.pypy.org Thu Sep 3 11:39:21 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 11:39:21 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: Rename last_cc to guard_success_cc to make it clearer what direction Message-ID: <20150903093921.914221C023F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79389:530e1bd01736 Date: 2015-09-03 11:39 +0200 http://bitbucket.org/pypy/pypy/changeset/530e1bd01736/ Log: Rename last_cc to guard_success_cc to make it clearer what direction this condition is supposed to be read. Remove a dummy reg alloc in consider_cond_call(). diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -726,10 +726,10 @@ def _assemble(self, regalloc, inputargs, operations): self._regalloc = regalloc - self.last_cc = rx86.cond_none + self.guard_success_cc = rx86.cond_none regalloc.compute_hint_frame_locations(operations) regalloc.walk_operations(inputargs, operations) - assert self.last_cc == rx86.cond_none + assert self.guard_success_cc == rx86.cond_none if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging frame_depth = regalloc.get_final_frame_depth() @@ -977,9 +977,9 @@ # "propagate it between this operation and the next guard by keeping # it in the cc". In the uncommon case, result_loc is another # register, and we emit a load from the cc into this register. - assert self.last_cc == rx86.cond_none + assert self.guard_success_cc == rx86.cond_none if result_loc is ebp: - self.last_cc = cond + self.guard_success_cc = cond else: rl = result_loc.lowest8bits() self.mc.SET_ir(cond, rl.value) @@ -1551,13 +1551,13 @@ genop_guard_guard_nonnull = genop_guard_guard_true def genop_guard_guard_false(self, guard_op, guard_token, locs, resloc): - self.last_cc = rx86.invert_condition(self.last_cc) + self.guard_success_cc = rx86.invert_condition(self.guard_success_cc) self.implement_guard(guard_token) genop_guard_guard_isnull = genop_guard_guard_false def genop_guard_guard_no_exception(self, guard_op, guard_token, locs, ign): self.mc.CMP(heap(self.cpu.pos_exception()), imm0) - self.last_cc = rx86.Conditions['Z'] + self.guard_success_cc = rx86.Conditions['Z'] self.implement_guard(guard_token) # If the previous operation was a COND_CALL, overwrite its conditional # jump to jump over this GUARD_NO_EXCEPTION as well, if we can @@ -1578,7 +1578,7 @@ loc1 = locs[1] self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) - self.last_cc = rx86.Conditions['E'] + self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) self._store_and_reset_exception(self.mc, resloc) @@ -1617,11 +1617,11 @@ genop_int_mul_ovf = genop_int_mul def genop_guard_guard_no_overflow(self, guard_op, guard_token, locs, ign): - self.last_cc = rx86.Conditions['NO'] + self.guard_success_cc = rx86.Conditions['NO'] self.implement_guard(guard_token) def genop_guard_guard_overflow(self, guard_op, guard_token, locs, ign): - self.last_cc = rx86.Conditions['O'] + self.guard_success_cc = rx86.Conditions['O'] self.implement_guard(guard_token) def genop_guard_guard_value(self, guard_op, guard_token, locs, ign): @@ -1630,7 +1630,7 @@ self.mc.UCOMISD(locs[0], locs[1]) else: self.mc.CMP(locs[0], locs[1]) - self.last_cc = rx86.Conditions['E'] + self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) def _cmp_guard_class(self, locs): @@ -1668,7 +1668,7 @@ def genop_guard_guard_class(self, guard_op, guard_token, locs, ign): self._cmp_guard_class(locs) - self.last_cc = rx86.Conditions['E'] + self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) def genop_guard_guard_nonnull_class(self, guard_op, guard_token, locs, ign): @@ -1682,7 +1682,7 @@ assert 0 < offset <= 127 self.mc.overwrite(jb_location-1, chr(offset)) # - self.last_cc = rx86.Conditions['E'] + self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) def implement_guard_recovery(self, guard_opnum, faildescr, failargs, @@ -1850,9 +1850,9 @@ def implement_guard(self, guard_token): # These jumps are patched later. - assert self.last_cc >= 0 - self.mc.J_il(rx86.invert_condition(self.last_cc), 0) - self.last_cc = rx86.cond_none + assert self.guard_success_cc >= 0 + self.mc.J_il(rx86.invert_condition(self.guard_success_cc), 0) + self.guard_success_cc = rx86.cond_none guard_token.pos_jump_offset = self.mc.get_relative_pos() - 4 self.pending_guard_tokens.append(guard_token) @@ -1900,7 +1900,7 @@ def genop_guard_guard_not_forced(self, guard_op, guard_token, locs, resloc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.CMP_bi(ofs, 0) - self.last_cc = rx86.Conditions['E'] + self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) def genop_call_may_force(self, op, arglocs, result_loc): @@ -2139,11 +2139,12 @@ def label(self): self._check_frame_depth_debug(self.mc) - def cond_call(self, op, gcmap, loc_cond, imm_func, arglocs): - assert self.last_cc >= 0 - self.mc.J_il8(rx86.invert_condition(self.last_cc), 0) # patched later + def cond_call(self, op, gcmap, imm_func, arglocs): + assert self.guard_success_cc >= 0 + self.mc.J_il8(rx86.invert_condition(self.guard_success_cc), 0) + # patched later jmp_adr = self.mc.get_relative_pos() - self.last_cc = rx86.cond_none + self.guard_success_cc = rx86.cond_none # self.push_gcmap(self.mc, gcmap, store=True) # diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -362,9 +362,9 @@ return self.rm.loc(v) def load_condition_into_cc(self, box): - if self.assembler.last_cc == rx86.cond_none: + if self.assembler.guard_success_cc == rx86.cond_none: self.assembler.test_location(self.loc(box)) - self.assembler.last_cc = rx86.Conditions['NZ'] + self.assembler.guard_success_cc = rx86.Conditions['NZ'] def _consider_guard_cc(self, op): self.load_condition_into_cc(op.getarg(0)) @@ -848,14 +848,13 @@ assert op.result is None args = op.getarglist() assert 2 <= len(args) <= 4 + 2 # maximum 4 arguments - loc_cond = self.make_sure_var_in_reg(args[0], args) v = args[1] assert isinstance(v, Const) imm_func = self.rm.convert_to_imm(v) arglocs = [self.loc(args[i]) for i in range(2, len(args))] gcmap = self.get_gcmap() self.load_condition_into_cc(op.getarg(0)) - self.assembler.cond_call(op, gcmap, loc_cond, imm_func, arglocs) + self.assembler.cond_call(op, gcmap, imm_func, arglocs) def consider_call_malloc_nursery(self, op): size_box = op.getarg(0) From noreply at buildbot.pypy.org Thu Sep 3 12:37:11 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 12:37:11 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: Right, write_fence() is done by stm_allocate_preexisting(), which Message-ID: <20150903103711.CFD971C023F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: use-gcc Changeset: r1952:4b10f9b403dd Date: 2015-09-03 12:37 +0200 http://bitbucket.org/pypy/stmgc/changeset/4b10f9b403dd/ Log: Right, write_fence() is done by stm_allocate_preexisting(), which guarantees that it returns an object that is already correct when viewed from other threads. diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -326,12 +326,6 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; - /* make sure .object is NULL in all segments before - "publishing" the entry in the hashtable. In other words, - the following write_fence() prevents a partially - initialized 'entry' from showing up in table->items[i], - where it could be read from other threads. */ - write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ From noreply at buildbot.pypy.org Thu Sep 3 15:57:22 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 3 Sep 2015 15:57:22 +0200 (CEST) Subject: [pypy-commit] pypy default: Kill old method Message-ID: <20150903135722.5C9EA1C01F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79390:f0916ec92e33 Date: 2015-09-03 15:57 +0200 http://bitbucket.org/pypy/pypy/changeset/f0916ec92e33/ Log: Kill old method diff --git a/rpython/jit/backend/arm/runner.py b/rpython/jit/backend/arm/runner.py --- a/rpython/jit/backend/arm/runner.py +++ b/rpython/jit/backend/arm/runner.py @@ -38,12 +38,6 @@ def set_debug(self, flag): return self.assembler.set_debug(flag) - def get_failargs_limit(self): - if self.opts is not None: - return self.opts.failargs_limit - else: - return 1000 - def setup(self): self.assembler = AssemblerARM(self, self.translate_support_code) diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py --- a/rpython/jit/backend/x86/runner.py +++ b/rpython/jit/backend/x86/runner.py @@ -49,12 +49,6 @@ def set_debug(self, flag): return self.assembler.set_debug(flag) - def get_failargs_limit(self): - if self.opts is not None: - return self.opts.failargs_limit - else: - return 1000 - def setup(self): self.assembler = Assembler386(self, self.translate_support_code) diff --git a/rpython/jit/backend/x86/test/test_assembler.py b/rpython/jit/backend/x86/test/test_assembler.py --- a/rpython/jit/backend/x86/test/test_assembler.py +++ b/rpython/jit/backend/x86/test/test_assembler.py @@ -26,9 +26,6 @@ assert num == 0x1C3 return FakeFailDescr() - def get_failargs_limit(self): - return 1000 - class FakeMC: def __init__(self): self.content = [] From noreply at buildbot.pypy.org Thu Sep 3 18:34:49 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:34:49 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: track descrs a bit differently Message-ID: <20150903163449.B53311C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79391:64b6bc2604a9 Date: 2015-09-03 18:08 +0200 http://bitbucket.org/pypy/pypy/changeset/64b6bc2604a9/ Log: track descrs a bit differently 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 @@ -104,11 +104,11 @@ short.append(op) class AbstractVirtualPtrInfo(NonNullPtrInfo): - _attrs_ = ('_cached_vinfo', 'vdescr') - # XXX merge _cached_vinfo with vdescr + _attrs_ = ('_cached_vinfo', 'descr', '_is_virtual') + # XXX merge _cached_vinfo with descr _cached_vinfo = None - vdescr = None + descr = None def force_box(self, op, optforce): if self.is_virtual(): @@ -117,9 +117,8 @@ if self._is_immutable_and_filled_with_constants(optforce.optimizer): constptr = optforce.optimizer.constant_fold(op) op.set_forwarded(constptr) - descr = self.vdescr - self.vdescr = None - self._force_elements_immutable(descr, constptr, optforce) + self._is_virtual = False + self._force_elements_immutable(self.descr, constptr, optforce) return constptr # op.set_forwarded(None) @@ -127,8 +126,8 @@ newop = optforce.getlastop() op.set_forwarded(newop) newop.set_forwarded(self) - descr = self.vdescr - self.vdescr = None + descr = self.descr + self._is_virtual = False self._force_elements(newop, optforce, descr) return newop return op @@ -137,7 +136,7 @@ return self.force_box(op, optforce) def is_virtual(self): - return self.vdescr is not None + return self._is_virtual class AbstractStructPtrInfo(AbstractVirtualPtrInfo): _attrs_ = ('_fields',) @@ -147,6 +146,7 @@ if self._fields is None: self._fields = [None] * len(descr.get_all_fielddescrs()) if index >= len(self._fields): + self.descr = descr # a more precise descr # we found out a subclass with more fields extra_len = len(descr.get_all_fielddescrs()) - len(self._fields) self._fields = self._fields + [None] * extra_len @@ -205,7 +205,7 @@ return op def _visitor_walk_recursive(self, instbox, visitor, optimizer): - lst = self.vdescr.get_all_fielddescrs() + lst = self.descr.get_all_fielddescrs() assert self.is_virtual() visitor.register_virtual_fields(instbox, [optimizer.get_box_replacement(box) @@ -235,7 +235,7 @@ # which also answers True to the same question. # assert self.is_virtual() - if not self.vdescr.is_immutable(): + if not self.descr.is_immutable(): return False if memo is not None and self in memo: return True # recursive case: assume yes @@ -271,18 +271,21 @@ _attrs_ = ('_known_class',) _fields = None - def __init__(self, known_class=None, vdescr=None): + def __init__(self, descr=None, known_class=None, is_virtual=False): self._known_class = known_class - self.vdescr = vdescr + # that's a descr of best-known class, can be actually a subclass + # of the class described in descr + self.descr = descr + self._is_virtual = is_virtual def get_known_class(self, cpu): return self._known_class @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): - fielddescrs = self.vdescr.get_all_fielddescrs() + fielddescrs = self.descr.get_all_fielddescrs() assert self.is_virtual() - return visitor.visit_virtual(self.vdescr, fielddescrs) + return visitor.visit_virtual(self.descr, fielddescrs) def make_guards(self, op, short): if self._known_class is not None: @@ -293,14 +296,15 @@ AbstractStructPtrInfo.make_guards(self, op, short) class StructPtrInfo(AbstractStructPtrInfo): - def __init__(self, vdescr=None): - self.vdescr = vdescr + def __init__(self, descr, is_virtual=False): + self.descr = descr + self._is_virtual = is_virtual @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): - fielddescrs = self.vdescr.get_all_fielddescrs() + fielddescrs = self.descr.get_all_fielddescrs() assert self.is_virtual() - return visitor.visit_vstruct(self.vdescr, fielddescrs) + return visitor.visit_vstruct(self.descr, fielddescrs) class AbstractRawPtrInfo(AbstractVirtualPtrInfo): def _visitor_walk_recursive(self, op, visitor, optimizer): @@ -400,19 +404,19 @@ return visitor.visit_vrawslice(self.offset) class ArrayPtrInfo(AbstractVirtualPtrInfo): - _attrs_ = ('length', '_items', 'lenbound', '_clear', 'arraydescr') + _attrs_ = ('length', '_items', 'lenbound', '_clear', 'descr', + '_is_virtual') _items = None lenbound = None length = -1 - def __init__(self, arraydescr, const=None, size=0, clear=False, - vdescr=None): + def __init__(self, descr, const=None, size=0, clear=False, + is_virtual=False): from rpython.jit.metainterp.optimizeopt import intutils - self.vdescr = vdescr - self.arraydescr = arraydescr - if vdescr is not None: - assert vdescr is arraydescr + self.descr = descr + self._is_virtual = is_virtual + if is_virtual: self._init_items(const, size, clear) self.lenbound = intutils.ConstIntBound(size) self._clear = clear @@ -437,15 +441,15 @@ return self._items def copy_fields_to_const(self, constinfo, optheap): - arraydescr = self.arraydescr + descr = self.descr if self._items is not None: - info = constinfo._get_array_info(arraydescr, optheap) + info = constinfo._get_array_info(descr, optheap) assert isinstance(info, ArrayPtrInfo) info._items = self._items[:] def _force_elements(self, op, optforce, descr): - arraydescr = op.getdescr() - const = optforce.new_const_item(self.arraydescr) + descr = op.getdescr() + const = optforce.new_const_item(self.descr) for i in range(self.length): item = self._items[i] if item is None or self._clear and const.same_constant(item): @@ -453,7 +457,7 @@ subbox = optforce.force_box(item) setop = ResOperation(rop.SETARRAYITEM_GC, [op, ConstInt(i), subbox], - descr=arraydescr) + descr=descr) self._items[i] = None optforce.emit_operation(setop) optforce.pure_from_args(rop.ARRAYLEN_GC, [op], ConstInt(len(self._items))) @@ -490,7 +494,7 @@ @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): - return visitor.visit_varray(self.vdescr, self._clear) + return visitor.visit_varray(self.descr, self._clear) def produce_short_preamble_ops(self, structbox, descr, index, optimizer, shortboxes): @@ -522,19 +526,20 @@ def make_guards(self, op, short): AbstractVirtualPtrInfo.make_guards(self, op, short) if self.lenbound is not None: - lenop = ResOperation(rop.ARRAYLEN_GC, [op], descr=self.arraydescr) + lenop = ResOperation(rop.ARRAYLEN_GC, [op], descr=self.descr) short.append(lenop) self.lenbound.make_guards(lenop, short) class ArrayStructInfo(ArrayPtrInfo): - def __init__(self, size, vdescr=None): + def __init__(self, descr, size, is_virtual=False): from rpython.jit.metainterp.optimizeopt import intutils self.length = size - lgt = len(vdescr.get_all_fielddescrs()) + lgt = len(descr.get_all_fielddescrs()) self.lenbound = intutils.ConstIntBound(size) - self.vdescr = vdescr + self.descr = descr self._items = [None] * (size * lgt) + self._is_virtual = is_virtual def _compute_index(self, index, fielddescr): all_fdescrs = fielddescr.get_arraydescr().get_all_fielddescrs() @@ -571,7 +576,7 @@ itemops = [optimizer.get_box_replacement(item) for item in self._items] visitor.register_virtual_fields(instbox, itemops) - fielddescrs = self.vdescr.get_all_fielddescrs() + fielddescrs = self.descr.get_all_fielddescrs() i = 0 for index in range(self.getlength()): for flddescr in fielddescrs: @@ -586,8 +591,8 @@ @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): - flddescrs = self.vdescr.get_all_fielddescrs() - return visitor.visit_varraystruct(self.vdescr, self.getlength(), + flddescrs = self.descr.get_all_fielddescrs() + return visitor.visit_varraystruct(self.descr, self.getlength(), flddescrs) class ConstPtrInfo(PtrInfo): @@ -602,24 +607,24 @@ def make_guards(self, op, short): short.append(ResOperation(rop.GUARD_VALUE, [op, self._const])) - def _get_info(self, optheap): + def _get_info(self, descr, optheap): ref = self._const.getref_base() info = optheap.const_infos.get(ref, None) if info is None: - info = StructPtrInfo() + info = StructPtrInfo(descr) optheap.const_infos[ref] = info return info - def _get_array_info(self, arraydescr, optheap): + def _get_array_info(self, descr, optheap): ref = self._const.getref_base() info = optheap.const_infos.get(ref, None) if info is None: - info = ArrayPtrInfo(arraydescr) + info = ArrayPtrInfo(descr) optheap.const_infos[ref] = info return info def getfield(self, descr, optheap=None): - info = self._get_info(optheap) + info = self._get_info(descr.get_parent_descr(), optheap) return info.getfield(descr) def getitem(self, descr, index, optheap=None): @@ -631,7 +636,7 @@ info.setitem(descr, index, struct, op, cf) def setfield(self, descr, struct, op, optheap=None, cf=None): - info = self._get_info(optheap) + info = self._get_info(descr.get_parent_descr(), optheap) info.setfield(descr, struct, op, optheap, cf) def is_null(self): 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 @@ -449,13 +449,13 @@ assert opinfo is None or opinfo.__class__ is info.NonNullPtrInfo if (op.is_getfield() or op.getopnum() == rop.SETFIELD_GC or op.getopnum() == rop.QUASIIMMUT_FIELD): - is_object = op.getdescr().get_parent_descr().is_object() - if is_object: - opinfo = info.InstancePtrInfo() + descr = op.getdescr() + parent_descr = descr.get_parent_descr() + if parent_descr.is_object(): + opinfo = info.InstancePtrInfo(parent_descr) else: - opinfo = info.StructPtrInfo() - opinfo.init_fields(op.getdescr().get_parent_descr(), - op.getdescr().get_index()) + opinfo = info.StructPtrInfo(parent_descr) + opinfo.init_fields(parent_descr, descr.get_index()) elif (op.is_getarrayitem() or op.getopnum() == rop.SETARRAYITEM_GC or op.getopnum() == rop.ARRAYLEN_GC): opinfo = info.ArrayPtrInfo(op.getdescr()) diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -15,7 +15,7 @@ _last_guard_not_forced_2 = None def make_virtual(self, known_class, source_op, descr): - opinfo = info.InstancePtrInfo(known_class, vdescr=descr) + opinfo = info.InstancePtrInfo(descr, known_class, is_virtual=True) opinfo.init_fields(descr, 0) newop = self.replace_op_with(source_op, source_op.getopnum()) newop.set_forwarded(opinfo) @@ -24,17 +24,17 @@ def make_varray(self, arraydescr, size, source_op, clear=False): if arraydescr.is_array_of_structs(): assert clear - opinfo = info.ArrayStructInfo(size, vdescr=arraydescr) + opinfo = info.ArrayStructInfo(arraydescr, size, is_virtual=True) else: const = self.new_const_item(arraydescr) opinfo = info.ArrayPtrInfo(arraydescr, const, size, clear, - vdescr=arraydescr) + is_virtual=True) newop = self.replace_op_with(source_op, source_op.getopnum()) newop.set_forwarded(opinfo) return opinfo def make_vstruct(self, structdescr, source_op): - opinfo = info.StructPtrInfo(vdescr=structdescr) + opinfo = info.StructPtrInfo(structdescr, is_virtual=True) opinfo.init_fields(structdescr, 0) newop = self.replace_op_with(source_op, source_op.getopnum()) newop.set_forwarded(opinfo) diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -601,6 +601,7 @@ class AbstractVArrayInfo(AbstractVirtualInfo): def __init__(self, arraydescr): + assert arraydescr is not None self.arraydescr = arraydescr #self.fieldnums = ... From noreply at buildbot.pypy.org Thu Sep 3 18:34:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:34:51 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: progress Message-ID: <20150903163451.D03FD1C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79392:80aff6489027 Date: 2015-09-03 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/80aff6489027/ Log: progress 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 @@ -289,9 +289,17 @@ def make_guards(self, op, short): if self._known_class is not None: - op = ResOperation(rop.GUARD_NONNULL_CLASS, [op, self._known_class], - None) - short.append(op) + short.extend([ + ResOperation(rop.GUARD_NONNULL, [op], None), + ResOperation(rop.GUARD_IS_OBJECT, [op], None), + ResOperation(rop.GUARD_CLASS, [op, self._known_class], None) + ]) + elif self.descr is not None: + short.extend([ + ResOperation(rop.GUARD_NONNULL, [op], None), + ResOperation(rop.GUARD_IS_OBJECT, [op], None), + xx + ]) else: AbstractStructPtrInfo.make_guards(self, op, short) @@ -300,6 +308,9 @@ self.descr = descr self._is_virtual = is_virtual + def make_guards(self, op, short): + xxx + @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): fielddescrs = self.descr.get_all_fielddescrs() 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 @@ -94,7 +94,7 @@ last_guard_pos = opinfo.get_last_guard_pos() else: last_guard_pos = -1 - opinfo = info.InstancePtrInfo(class_const) + opinfo = info.InstancePtrInfo(None, class_const) opinfo.last_guard_pos = last_guard_pos op.set_forwarded(opinfo) if update_last_guard: From noreply at buildbot.pypy.org Thu Sep 3 18:34:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:34:54 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150903163454.4F7161C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79393:0cd368883dd1 Date: 2015-09-03 18:17 +0200 http://bitbucket.org/pypy/pypy/changeset/0cd368883dd1/ Log: merge 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 @@ -913,9 +913,25 @@ if TYPE != typeid.STRUCT_OR_ARRAY: self.fail_guard(descr) - def execute_guard_nonnull_gc_type(self, descr, arg, typeid): - self.execute_guard_nonnull(descr, arg) - self.execute_guard_gc_type(descr, arg, typeid) + def execute_guard_is_object(self, descr, arg): + TYPE = arg._obj.container._TYPE + while TYPE is not rclass.OBJECT: + if not isinstance(TYPE, lltype.GcStruct): # or TYPE is None + self.fail_guard(descr) + return + _, TYPE = TYPE._first_struct() + + def execute_guard_subclass(self, descr, arg, klass): + value = lltype.cast_opaque_ptr(rclass.OBJECTPTR, arg) + expected_class = llmemory.cast_adr_to_ptr( + llmemory.cast_int_to_adr(klass), + rclass.CLASSTYPE) + if (expected_class.subclassrange_min + <= value.typeptr.subclassrange_min + <= expected_class.subclassrange_max): + pass + else: + self.fail_guard(descr) def execute_guard_no_exception(self, descr): if self.last_exception is not None: diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -4840,9 +4840,6 @@ c_typeid = ConstInt(descr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void') assert not self.guard_failed - self.execute_operation(rop.GUARD_NONNULL_GC_TYPE, [t_box, c_typeid], - 'void') - assert not self.guard_failed def test_passing_guard_gc_type_array(self): if not self.cpu.supports_guard_gc_type: @@ -4852,9 +4849,6 @@ c_typeid = ConstInt(arraydescr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void') assert not self.guard_failed - self.execute_operation(rop.GUARD_NONNULL_GC_TYPE, [a_box, c_typeid], - 'void') - assert not self.guard_failed def test_failing_guard_gc_type(self): if not self.cpu.supports_guard_gc_type: @@ -4866,17 +4860,78 @@ c_ttypeid = ConstInt(tdescr.get_type_id()) c_utypeid = ConstInt(udescr.get_type_id()) c_atypeid = ConstInt(adescr.get_type_id()) - null_box = self.null_instance() for opname, args in [(rop.GUARD_GC_TYPE, [t_box, c_utypeid]), (rop.GUARD_GC_TYPE, [u_box, c_ttypeid]), (rop.GUARD_GC_TYPE, [a_box, c_utypeid]), (rop.GUARD_GC_TYPE, [t_box, c_atypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [t_box, c_utypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [u_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [a_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [u_box, c_atypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [null_box, c_ttypeid]), - (rop.GUARD_NONNULL_GC_TYPE, [null_box, c_atypeid]), ]: assert self.execute_operation(opname, args, 'void') == None assert self.guard_failed + + def test_guard_is_object(self): + if not self.cpu.supports_guard_gc_type: + py.test.skip("guard_gc_type not available") + t_box, _, _ = self.alloc_instance(self.T) + self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void') + # + assert not self.guard_failed + a_box, _ = self.alloc_array_of(rffi.SHORT, 342) + self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void') + assert self.guard_failed + # + S = lltype.GcStruct('S') + s = lltype.malloc(S, immortal=True, zero=True) + s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s)) + self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void') + assert self.guard_failed + + def test_guard_subclass(self): + if not self.cpu.supports_guard_gc_type: + py.test.skip("guard_gc_type not available") + + xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + xtp.subclassrange_min = 1 + xtp.subclassrange_max = 3 + X = lltype.GcStruct('X', ('parent', rclass.OBJECT), + hints={'vtable': xtp._obj}) + xptr = lltype.malloc(X) + xptr.parent.typeptr = xtp + x_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, xptr)) + X_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(xtp))) + + ytp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + ytp.subclassrange_min = 2 + ytp.subclassrange_max = 2 + assert rclass.ll_issubclass(ytp, xtp) + Y = lltype.GcStruct('Y', ('parent', X), + hints={'vtable': ytp._obj}) + yptr = lltype.malloc(Y) + yptr.parent.parent.typeptr = ytp + y_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, yptr)) + Y_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ytp))) + + ztp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) + ztp.subclassrange_min = 4 + ztp.subclassrange_max = 5 + assert not rclass.ll_issubclass(ztp, xtp) + assert not rclass.ll_issubclass(xtp, ztp) + Z = lltype.GcStruct('Z', ('parent', rclass.OBJECT), + hints={'vtable': ztp._obj}) + zptr = lltype.malloc(Z) + zptr.parent.typeptr = ztp + z_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, zptr)) + Z_box = ConstInt(heaptracker.adr2int(llmemory.cast_ptr_to_adr(ztp))) + + for num, arg, klass, is_subclass in [ + (1, x_box, X_box, True), + (2, x_box, Y_box, False), + (3, x_box, Z_box, False), + (4, y_box, X_box, True), + (5, y_box, Y_box, True), + (6, y_box, Z_box, False), + (7, z_box, X_box, False), + (8, z_box, Y_box, False), + (9, z_box, Z_box, True), + ]: + self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void') + assert self.guard_failed == (not is_subclass) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1734,7 +1734,9 @@ self.mc.CMP(locs[0], locs[1]) self.implement_guard(guard_token, 'NE') - def _cmp_guard_class(self, loc_ptr, loc_classptr): + def _cmp_guard_class(self, locs): + loc_ptr = locs[0] + loc_classptr = locs[1] offset = self.cpu.vtable_offset if offset is not None: self.mc.CMP(mem(loc_ptr, offset), loc_classptr) @@ -1770,18 +1772,8 @@ assert isinstance(loc_expected_typeid, ImmedLoc) self.mc.CMP32_mi((loc_ptr.value, 0), loc_expected_typeid.value) - def _cmp_guard_class_or_gc_type(self, guard_op, locs): - if ( guard_op.getopnum() == rop.GUARD_CLASS or - guard_op.getopnum() == rop.GUARD_NONNULL_CLASS): - self._cmp_guard_class(locs[0], locs[1]) - elif (guard_op.getopnum() == rop.GUARD_GC_TYPE or - guard_op.getopnum() == rop.GUARD_NONNULL_GC_TYPE): - self._cmp_guard_gc_type(locs[0], locs[1]) - else: - assert 0 - def genop_guard_guard_class(self, ign_1, guard_op, guard_token, locs, ign_2): - self._cmp_guard_class_or_gc_type(guard_op, locs) + self._cmp_guard_class(locs) self.implement_guard(guard_token, 'NE') def genop_guard_guard_nonnull_class(self, ign_1, guard_op, @@ -1790,7 +1782,7 @@ # Patched below self.mc.J_il8(rx86.Conditions['B'], 0) jb_location = self.mc.get_relative_pos() - self._cmp_guard_class_or_gc_type(guard_op, locs) + self._cmp_guard_class(locs) # patch the JB above offset = self.mc.get_relative_pos() - jb_location assert 0 < offset <= 127 @@ -1798,8 +1790,10 @@ # self.implement_guard(guard_token, 'NE') - genop_guard_guard_gc_type = genop_guard_guard_class - genop_guard_guard_nonnull_gc_type = genop_guard_guard_nonnull_class + def genop_guard_guard_gc_type(self, ign_1, guard_op, + guard_token, locs, ign_2): + self._cmp_guard_gc_type(locs[0], locs[1]) + self.implement_guard(guard_token, 'NE') def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -429,7 +429,12 @@ consider_guard_nonnull_class = consider_guard_class consider_guard_gc_type = consider_guard_class - consider_guard_nonnull_gc_type = consider_guard_class + + def consider_guard_is_object(self, op): + xxx + + def consider_guard_subclass(self, op): + xxx def _consider_binop_part(self, op, symm=False): x = op.getarg(0) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -661,8 +661,9 @@ 'GUARD_NONNULL/1d/n', 'GUARD_ISNULL/1d/n', 'GUARD_NONNULL_CLASS/2d/n', - 'GUARD_GC_TYPE/2d/n', - 'GUARD_NONNULL_GC_TYPE/2d/n', + 'GUARD_GC_TYPE/2d/n', # only if supports_guard_gc_type + 'GUARD_IS_OBJECT/1d/n', # only if supports_guard_gc_type + 'GUARD_SUBCLASS/2d/n', # only if supports_guard_gc_type '_GUARD_FOLDABLE_LAST', 'GUARD_NO_EXCEPTION/0d/n', # may be called with an exception currently set 'GUARD_EXCEPTION/1d/r', # may be called with an exception currently set From noreply at buildbot.pypy.org Thu Sep 3 18:34:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:34:56 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: continue whacking, next step is fighting with symbolic comparison Message-ID: <20150903163456.7AFDA1C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79394:de93952a28cf Date: 2015-09-03 18:34 +0200 http://bitbucket.org/pypy/pypy/changeset/de93952a28cf/ Log: continue whacking, next step is fighting with symbolic comparison 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 @@ -33,6 +33,12 @@ def is_nonnull(self): return False + def is_about_object(self): + return False + + def get_descr(self): + return None + def is_null(self): return False @@ -110,6 +116,9 @@ _cached_vinfo = None descr = None + def get_descr(self): + return self.descr + def force_box(self, op, optforce): if self.is_virtual(): optforce.forget_numberings() @@ -281,6 +290,9 @@ def get_known_class(self, cpu): return self._known_class + def is_about_object(self): + return True + @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): fielddescrs = self.descr.get_all_fielddescrs() @@ -298,7 +310,8 @@ short.extend([ ResOperation(rop.GUARD_NONNULL, [op], None), ResOperation(rop.GUARD_IS_OBJECT, [op], None), - xx + ResOperation(rop.GUARD_SUBCLASS, [op, + ConstInt(self.descr.get_vtable())], None) ]) else: AbstractStructPtrInfo.make_guards(self, op, short) @@ -309,7 +322,12 @@ self._is_virtual = is_virtual def make_guards(self, op, short): - xxx + if self.descr is not None: + c_typeid = ConstInt(self.descr.get_type_id()) + short.extend([ + ResOperation(rop.GUARD_NONNULL, [op], None), + ResOperation(rop.GUARD_GC_TYPE, [op, c_typeid], None) + ]) @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): @@ -536,6 +554,8 @@ def make_guards(self, op, short): AbstractVirtualPtrInfo.make_guards(self, op, short) + c_type_id = ConstInt(self.descr.get_type_id()) + short.append(ResOperation(rop.GUARD_GC_TYPE, [op, c_type_id], None)) if self.lenbound is not None: lenop = ResOperation(rop.ARRAYLEN_GC, [op], descr=self.descr) short.append(lenop) diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -292,6 +292,34 @@ self.emit_operation(op) self.make_constant(op.getarg(0), self.optimizer.cpu.ts.CONST_NULL) + def optimize_GUARD_IS_OBJECT(self, op): + info = self.getptrinfo(op.getarg(0)) + if info is not None and info.is_about_object(): + return + self.emit_operation(op) + + def optimize_GUARD_GC_TYPE(self, op): + info = self.getptrinfo(op.getarg(0)) + if info is not None and info.get_descr() is not None: + if info.get_descr().get_type_id() != op.getarg(1).getint(): + raise InvalidLoop("wrong GC types passed around!") + return + self.emit_operation(op) + + def optimize_GUARD_SUBCLASS(self, op): + info = self.getptrinfo(op.getarg(0)) + if info is not None and info.is_about_object(): + known_class = info.get_known_class(self.optimizer.cpu) + if known_class: + if known_class.getint() == op.getarg(1).getint(): + # XXX subclass check + return + elif info.get_descr() is not None: + if info.get_descr().get_vtable() == op.getarg(1).getint(): + # XXX check for actual subclass? + return + self.emit_operation(op) + def optimize_GUARD_NONNULL(self, op): opinfo = self.getptrinfo(op.getarg(0)) if opinfo is not None: 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 @@ -886,6 +886,8 @@ short = """ [p1, p2] guard_nonnull(p1) [] + guard_is_object(p1) [] + guard_subclass(p1, ConstClass(node_vtable)) [] i1 = getfield_gc_i(p1, descr=valuedescr) jump(i1) """ diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -54,7 +54,7 @@ if known_class: self.make_constant_class(op, known_class, False) if isinstance(preamble_info, info.ArrayPtrInfo): - arr_info = info.ArrayPtrInfo(preamble_info.arraydescr) + arr_info = info.ArrayPtrInfo(preamble_info.descr) bound = preamble_info.getlenbound(None).clone() assert isinstance(bound, intutils.IntBound) arr_info.lenbound = bound From noreply at buildbot.pypy.org Thu Sep 3 18:35:47 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:35:47 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: add equality to llgraph faking of symbolics Message-ID: <20150903163547.688AE1C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79395:2786719da854 Date: 2015-09-03 18:35 +0200 http://bitbucket.org/pypy/pypy/changeset/2786719da854/ Log: add equality to llgraph faking of symbolics 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 @@ -93,6 +93,12 @@ def __init__(self, STRUCT_OR_ARRAY): self.STRUCT_OR_ARRAY = STRUCT_OR_ARRAY + def __eq__(self, other): + return self.STRUCT_OR_ARRAY is other.STRUCT_OR_ARRAY + + def __ne__(self, other): + return not self == other + class SizeDescr(AbstractDescr): def __init__(self, S, vtable, runner): assert not isinstance(vtable, bool) From noreply at buildbot.pypy.org Thu Sep 3 18:58:09 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 18:58:09 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: finish porting test_optimizeopt Message-ID: <20150903165809.CCD041C1358@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79396:7d1215a06ad4 Date: 2015-09-03 18:58 +0200 http://bitbucket.org/pypy/pypy/changeset/7d1215a06ad4/ Log: finish porting test_optimizeopt 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 @@ -149,10 +149,12 @@ class AbstractStructPtrInfo(AbstractVirtualPtrInfo): _attrs_ = ('_fields',) + _fields = None def init_fields(self, descr, index): if self._fields is None: + self.descr = descr self._fields = [None] * len(descr.get_all_fielddescrs()) if index >= len(self._fields): self.descr = descr # a more precise descr @@ -166,7 +168,7 @@ def copy_fields_to_const(self, constinfo, optheap): if self._fields is not None: - info = constinfo._get_info(optheap) + info = constinfo._get_info(self.descr, optheap) assert isinstance(info, AbstractStructPtrInfo) info._fields = self._fields[:] @@ -443,6 +445,7 @@ def __init__(self, descr, const=None, size=0, clear=False, is_virtual=False): from rpython.jit.metainterp.optimizeopt import intutils + assert descr is not None self.descr = descr self._is_virtual = is_virtual if is_virtual: 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 @@ -4675,7 +4675,7 @@ ops = """ [i0, p0] p1 = new_array(i0, descr=gcarraydescr) - i1 = arraylen_gc(p1) + i1 = arraylen_gc(p1, descr=gcarraydescr) i2 = int_gt(i1, -1) guard_true(i2) [] setarrayitem_gc(p0, 0, p1, descr=gcarraydescr) @@ -4685,7 +4685,7 @@ expected = """ [i0, p0] p1 = new_array(i0, descr=gcarraydescr) - i1 = arraylen_gc(p1) + i1 = arraylen_gc(p1, descr=gcarraydescr) setarrayitem_gc(p0, 0, p1, descr=gcarraydescr) jump(i0, p0) """ @@ -4735,14 +4735,14 @@ def test_bound_force_ge_zero(self): ops = """ [p0] - i0 = arraylen_gc(p0) + i0 = arraylen_gc(p0, descr=arraydescr) i1 = int_force_ge_zero(i0) escape_n(i1) jump(p0) """ preamble = """ [p0] - i0 = arraylen_gc(p0) + i0 = arraylen_gc(p0, descr=arraydescr) escape_n(i0) jump(p0, i0) """ @@ -7266,6 +7266,7 @@ short = """ [p1, p187, i184] guard_nonnull(p187) [] + guard_gc_type(p187, ConstInt(gcarraydescr_tid)) [] i10 = arraylen_gc(p187, descr=gcarraydescr) i11 = int_ge(i10, 43) guard_true(i11) [] @@ -7453,11 +7454,17 @@ """ short = """ [p0] - guard_nonnull_class(p0, ConstClass(node_vtable)) [] + guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_class(p0, ConstClass(node_vtable)) [] p1 = getfield_gc_r(p0, descr=nextdescr) - guard_nonnull_class(p1, ConstClass(node_vtable)) [] + guard_nonnull(p1) [] + guard_is_object(p1) [] + guard_class(p1, ConstClass(node_vtable)) [] p2 = getfield_gc_r(p1, descr=nextdescr) - guard_nonnull_class(p2, ConstClass(node_vtable)) [] + guard_nonnull(p2) [] + guard_is_object(p2) [] + guard_class(p2, ConstClass(node_vtable)) [] jump(p1) """ self.optimize_loop(ops, expected, expected_short=short) @@ -7628,7 +7635,7 @@ def test_loopinvariant_arraylen(self): ops = """ [p9] - i843 = arraylen_gc(p9) + i843 = arraylen_gc(p9, descr=arraydescr) call_n(i843, descr=nonwritedescr) jump(p9) """ @@ -7650,8 +7657,11 @@ short = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] + guard_gc_type(p1, ConstInt(gcarraydescr_tid)) [] i1 = arraylen_gc(p1, descr=gcarraydescr) i2 = int_ge(i1, 8) guard_true(i2) [] @@ -7746,14 +7756,14 @@ def test_loopinvariant_getarrayitem_gc_pure(self): ops = """ [p9, i1] - i843 = getarrayitem_gc_pure_i(p9, i1) + i843 = getarrayitem_gc_pure_i(p9, i1, descr=arraydescr) call_n(i843, descr=nonwritedescr) jump(p9, i1) """ expected = """ [p9, i1, i843] call_n(i843, descr=nonwritedescr) - ifoo = arraylen_gc(p9) + ifoo = arraylen_gc(p9, descr=arraydescr) jump(p9, i1, i843) """ self.optimize_loop(ops, expected) @@ -7762,25 +7772,28 @@ ops = """ [p0] p1 = getfield_gc_r(p0, descr=nextdescr) - p2 = getarrayitem_gc_pure_r(p1, 7, descr=) + p2 = getarrayitem_gc_pure_r(p1, 7, descr=gcarraydescr) call_n(p2, descr=nonwritedescr) jump(p0) """ short = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] - i1 = arraylen_gc(p1) + guard_gc_type(p1, ConstInt(gcarraydescr_tid)) [] + i1 = arraylen_gc(p1, descr=gcarraydescr) i2 = int_ge(i1, 8) guard_true(i2) [] - p2 = getarrayitem_gc_pure_r(p1, 7, descr=) + p2 = getarrayitem_gc_pure_r(p1, 7, descr=gcarraydescr) jump(p2, p1) """ expected = """ [p0, p2, p1] call_n(p2, descr=nonwritedescr) - i3 = arraylen_gc(p1) # Should be killed by backend + i3 = arraylen_gc(p1, descr=gcarraydescr) # Should be killed by backend jump(p0, p2, p1) """ self.optimize_loop(ops, expected, expected_short=short) @@ -7796,6 +7809,8 @@ short = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] i1 = strlen(p1) @@ -7827,6 +7842,8 @@ short = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] i1 = unicodelen(p1) @@ -7936,6 +7953,8 @@ short = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] i0 = getfield_gc_i(p0, descr=valuedescr) guard_value(i0, 1) [] jump() @@ -8297,6 +8316,8 @@ short = """ [p22, p18] guard_nonnull(p22) [] + guard_is_object(p22) [] + guard_subclass(p22, ConstClass(node_vtable)) [] i1 = getfield_gc_i(p22, descr=valuedescr) guard_value(i1, 2) [] jump() @@ -8329,6 +8350,8 @@ short = """ [p22, p18, i1] guard_nonnull(p22) [] + guard_is_object(p22) [] + guard_subclass(p22, ConstClass(node_vtable)) [] i2 = getfield_gc_i(p22, descr=valuedescr) jump(i2) """ 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 @@ -187,6 +187,7 @@ array2 = lltype.malloc(lltype.GcArray(lltype.Ptr(S)), 15, zero=True) array2ref = lltype.cast_opaque_ptr(llmemory.GCREF, array2) gcarraydescr = cpu.arraydescrof(lltype.GcArray(llmemory.GCREF)) + gcarraydescr_tid = gcarraydescr.get_type_id() floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) # a GcStruct not inheriting from OBJECT diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -50,6 +50,13 @@ return if op.is_constant(): return # nothing we can learn + if preamble_info.get_descr() is not None: + if isinstance(preamble_info, info.StructPtrInfo): + op.set_forwarded(info.StructPtrInfo( + preamble_info.get_descr())) + if isinstance(preamble_info, info.InstancePtrInfo): + op.set_forwarded(info.InstancePtrInfo( + preamble_info.get_descr())) known_class = preamble_info.get_known_class(self.cpu) if known_class: self.make_constant_class(op, known_class, False) diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -109,6 +109,8 @@ obj = self._consts[name] if typ == 'ptr': return self.model.ConstPtr(obj) + elif typ == 'int': + return self.model.ConstInt(obj) else: assert typ == 'class' return self.model.ConstInt(self.model.ptr_to_int(obj)) @@ -207,6 +209,9 @@ if arg.startswith('ConstClass('): name = arg[len('ConstClass('):-1] return self.get_const(name, 'class') + elif arg.startswith('ConstInt('): + name = arg[len('ConstInt('):-1] + return self.get_const(name, 'int') elif arg == 'None': return None elif arg == 'NULL': From noreply at buildbot.pypy.org Thu Sep 3 19:11:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 19:11:51 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: a few fixes + a failing test. I think guard_subclass implementation in llgraph is incorrect Message-ID: <20150903171151.507F51C01F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79397:5b24a245a731 Date: 2015-09-03 19:11 +0200 http://bitbucket.org/pypy/pypy/changeset/5b24a245a731/ Log: a few fixes + a failing test. I think guard_subclass implementation in llgraph is incorrect 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 @@ -20,6 +20,9 @@ def force_box(self, op, optforce): return op + def is_precise(self): + return False + def getconst(self): raise Exception("not a constant") @@ -119,6 +122,9 @@ def get_descr(self): return self.descr + def is_precise(self): + return True + def force_box(self, op, optforce): if self.is_virtual(): optforce.forget_numberings() diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -294,8 +294,11 @@ def optimize_GUARD_IS_OBJECT(self, op): info = self.getptrinfo(op.getarg(0)) - if info is not None and info.is_about_object(): - return + if info is not None: + if info.is_about_object(): + return + if info.is_precise(): + raise InvalidLoop() self.emit_operation(op) def optimize_GUARD_GC_TYPE(self, op): diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1,5 +1,5 @@ import py -from rpython.rlib.jit import JitDriver, hint, set_param +from rpython.rlib.jit import JitDriver, hint, set_param, dont_look_inside from rpython.rlib.objectmodel import compute_hash from rpython.jit.metainterp.warmspot import ll_meta_interp, get_stats from rpython.jit.metainterp.test.support import LLJitMixin @@ -953,5 +953,62 @@ res = self.meta_interp(f, [20, 10]) assert res == f(20, 10) + def test_subclasses_dont_match(self): + class A(object): + def __init__(self, val): + self.val = val + + def getval(self): + return self.val + + class B(A): + def __init__(self, foo, val): + self.foo = foo + self.val = val + self.val2 = val + + def getval(self): + return self.val2 + + class Container(object): + def __init__(self, x): + self.x = x + + myjitdriver = JitDriver(greens = [], reds = 'auto') + + @dont_look_inside + def externfn(a, i): + if i > 7: + return 1 + return 0 + + class Foo(Exception): + pass + + @dont_look_inside + def checkclass(a): + if type(a) is not B: + raise Foo() + + def f(n): + i = 0 + a = Container(B(A(n), n)) + b = Container(A(n)) + s = 0 + while i < n: + myjitdriver.jit_merge_point() + i += 1 + try: + checkclass(a.x) + except Foo: + pass + else: + s += a.x.val2 + if externfn(a, i): + a = b + + assert f(15) == self.meta_interp(f, [15]) + + class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Thu Sep 3 19:36:28 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 19:36:28 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: resolve some simple things Message-ID: <20150903173628.BD2F11C1378@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79398:1e7990e3b667 Date: 2015-09-03 19:36 +0200 http://bitbucket.org/pypy/pypy/changeset/1e7990e3b667/ Log: resolve some simple things 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 @@ -364,6 +364,9 @@ assert buffer is not None return buffer + def all_items(self): + return [] + def getitem_raw(self, offset, itemsize, descr): if not self.is_virtual(): raise InvalidRawOperation @@ -440,6 +443,7 @@ def visitor_dispatch_virtual_type(self, visitor): return visitor.visit_vrawslice(self.offset) + class ArrayPtrInfo(AbstractVirtualPtrInfo): _attrs_ = ('length', '_items', 'lenbound', '_clear', 'descr', '_is_virtual') diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py --- a/rpython/jit/metainterp/test/test_resume.py +++ b/rpython/jit/metainterp/test/test_resume.py @@ -1208,19 +1208,19 @@ vdescr = LLtypeMixin.nodesize2 ca = ConstAddr(LLtypeMixin.node_vtable_adr2, LLtypeMixin.cpu) - v4 = info.InstancePtrInfo(ca, vdescr) + v4 = info.InstancePtrInfo(vdescr, ca, True) b4s.set_forwarded(v4) v4.setfield(LLtypeMixin.nextdescr, ca, b2s) v4.setfield(LLtypeMixin.valuedescr, ca, b3s) v4.setfield(LLtypeMixin.otherdescr, ca, b5s) ca = ConstAddr(LLtypeMixin.node_vtable_adr, LLtypeMixin.cpu) - v2 = info.InstancePtrInfo(ca, LLtypeMixin.nodesize) + v2 = info.InstancePtrInfo(LLtypeMixin.nodesize, ca, True) v2.setfield(LLtypeMixin.nextdescr, b4s, ca) v2.setfield(LLtypeMixin.valuedescr, c1s, ca) b2s.set_forwarded(v2) - modifier.register_virtual_fields(b2s, [c1s, None, None, b4s]) - modifier.register_virtual_fields(b4s, [b3s, None, None, b2s, b5s]) + modifier.register_virtual_fields(b2s, [c1s, None, None, None, b4s]) + modifier.register_virtual_fields(b4s, [b3s, None, None, None, b2s, b5s]) liveboxes = [] modifier._number_virtuals(liveboxes, FakeOptimizer(), 0) @@ -1285,8 +1285,7 @@ modifier.liveboxes = {} modifier.vfieldboxes = {} - v2 = info.ArrayPtrInfo(LLtypeMixin.arraydescr, - vdescr=LLtypeMixin.arraydescr, size=2) + v2 = info.ArrayPtrInfo(LLtypeMixin.arraydescr, size=2, is_virtual=True) b2s.set_forwarded(v2) v2._items = [b4s, c1s] modifier.register_virtual_fields(b2s, [b4s, c1s]) @@ -1334,7 +1333,7 @@ modifier.liveboxes_from_env = {} modifier.liveboxes = {} modifier.vfieldboxes = {} - v2 = info.StructPtrInfo(LLtypeMixin.ssize) + v2 = info.StructPtrInfo(LLtypeMixin.ssize, is_virtual=True) b2s.set_forwarded(v2) v2.setfield(LLtypeMixin.adescr, b2s, c1s) v2.setfield(LLtypeMixin.abisdescr, b2s, c1s) From noreply at buildbot.pypy.org Thu Sep 3 20:05:26 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:05:26 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: write some tests and fix the random order Message-ID: <20150903180526.8AB6E1C1358@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79399:fb30f10ab865 Date: 2015-09-03 20:05 +0200 http://bitbucket.org/pypy/pypy/changeset/fb30f10ab865/ Log: write some tests and fix the random order 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 @@ -2743,6 +2743,11 @@ # # initialize p1.getref_base() to return a random pointer to a NODE # (it doesn't have to be self.nodeaddr, but it's convenient) + failargs = self.loop.operations[1].getfailargs() + if failargs[0].type == 'r': + values = [InputArgRef(self.nodeaddr), InputArgInt(0)] + else: + values = [InputArgInt(0), InputArgRef(self.nodeaddr)] assert hasattr(self.oparse.getvar('p1'), '_resref') self.oparse.getvar('p1')._resref = self.nodeaddr # @@ -2750,8 +2755,7 @@ ''' p1.nextdescr = p2 where p2 is a node_vtable, valuedescr=i2 - ''', rop.GUARD_TRUE, values=[InputArgRef(self.nodeaddr), - InputArgInt(0)]) + ''', rop.GUARD_TRUE, values=values) def test_expand_fail_lazy_setfield_2(self): ops = """ @@ -3637,7 +3641,7 @@ ops = """ [i0, p0] p1 = new_array(i0, descr=arraydescr) - i1 = arraylen_gc(p1) + i1 = arraylen_gc(p1, descr=arraydescr) i2 = int_gt(i1, -1) guard_true(i2) [] setarrayitem_gc(p0, 0, p1, descr=arraydescr) @@ -3647,7 +3651,7 @@ expected = """ [i0, p0] p1 = new_array(i0, descr=arraydescr) - i1 = arraylen_gc(p1) + i1 = arraylen_gc(p1, descr=arraydescr) setarrayitem_gc(p0, 0, p1, descr=arraydescr) jump(i0, p0) """ @@ -5805,5 +5809,29 @@ """ self.optimize_loop(ops, expected) + def test_remove_guard_gc_type(self): + ops = """ + [p0, p1] + setarrayitem_gc(p0, 1, p1, descr=gcarraydescr) + guard_gc_type(p0, ConstInt(gcarraydescr_tid)) [] + """ + expected = """ + [p0, p1] + setarrayitem_gc(p0, 1, p1, descr=gcarraydescr) + """ + self.optimize_loop(ops, expected) + + def test_remove_guard_is_object_1(self): + ops = """ + [p0] + guard_class(p0, ConstClass(node_vtable)) [] + guard_is_object(p0) [] + """ + expected = """ + [p0] + guard_class(p0, ConstClass(node_vtable)) [] + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Thu Sep 3 20:24:03 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:24:03 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: some passing tests and one failing, so we don't forget Message-ID: <20150903182403.53B851C1390@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79400:66aaa50b4f63 Date: 2015-09-03 20:14 +0200 http://bitbucket.org/pypy/pypy/changeset/66aaa50b4f63/ Log: some passing tests and one failing, so we don't forget diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -963,6 +963,9 @@ resumedescr = ResumeGuardOverflowDescr() elif opnum == rop.GUARD_NO_OVERFLOW: resumedescr = ResumeGuardNoOverflowDescr() + elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE): + # note - this only happens in tests + resumedescr = ResumeAtPositionDescr() else: assert False return resumedescr 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 @@ -5833,5 +5833,47 @@ """ self.optimize_loop(ops, expected) + def test_remove_guard_is_object_2(self): + ops = """ + [p0] + i1 = getfield_gc_i(p0, descr=valuedescr) + guard_is_object(p0) [] + finish(i1) + """ + expected = """ + [p0] + i1 = getfield_gc_i(p0, descr=valuedescr) + finish(i1) + """ + self.optimize_loop(ops, expected) + + def test_remove_guard_subclass_1(self): + ops = """ + [p0] + i1 = getfield_gc_i(p0, descr=valuedescr) + guard_subclass(p0, ConstClass(node_vtable)) [] + finish(i1) + """ + expected = """ + [p0] + i1 = getfield_gc_i(p0, descr=valuedescr) + finish(i1) + """ + self.optimize_loop(ops, expected) + + def test_remove_guard_subclass_2(self): + ops = """ + [p0] + p1 = getfield_gc_i(p0, descr=otherdescr) + guard_subclass(p0, ConstClass(node_vtable)) [] + finish(p1) + """ + expected = """ + [p0] + p1 = getfield_gc_i(p0, descr=otherdescr) + finish(p1) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Thu Sep 3 20:24:05 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:24:05 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: ups Message-ID: <20150903182405.B589F1C1390@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79401:9b54c2978f05 Date: 2015-09-03 20:21 +0200 http://bitbucket.org/pypy/pypy/changeset/9b54c2978f05/ Log: ups 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 @@ -302,6 +302,10 @@ return info.force_at_the_end_of_preamble(box, self.optearlyforce, rec) return box + if box.type == 'i': + info = self.getrawptrinfo(box) + return info.force_at_the_end_of_preamble(box, self.optearlyforce, + None) return box def flush(self): 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 @@ -8726,5 +8726,13 @@ """ self.optimize_loop(ops, expected, preamble) + def test_raw_buffer_in_preamble(self): + ops = """ + [i1] + i0 = call_i(123, 10, descr=raw_malloc_descr) + jump(i0) + """ + self.optimize_loop(ops, ops) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -350,8 +350,7 @@ constbox = None known_class = None - def __init__(self, cpu, type, info, is_opaque=False): - self.is_opaque = is_opaque + def __init__(self, cpu, type, info): if info and info.is_constant(): self.level = LEVEL_CONSTANT self.constbox = info.getconst() @@ -382,8 +381,6 @@ return False def _generate_guards(self, other, box, runtime_box, state): - if self.is_opaque: - box = None # generating guards for opaque pointers isn't safe # XXX This will always retrace instead of forcing anything which # might be what we want sometimes? if not isinstance(other, NotVirtualStateInfo): @@ -668,7 +665,6 @@ return VirtualState(state) def visit_not_virtual(self, box): - is_opaque = box in self.optimizer.opaque_pointers return NotVirtualStateInfo(self.optimizer.cpu, box.type, self.optimizer.getinfo(box)) From noreply at buildbot.pypy.org Thu Sep 3 20:24:07 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:24:07 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix for raw buffer tests Message-ID: <20150903182407.C91BF1C1390@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79402:853555a3255f Date: 2015-09-03 20:23 +0200 http://bitbucket.org/pypy/pypy/changeset/853555a3255f/ Log: fix for raw buffer tests 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 @@ -304,8 +304,9 @@ return box if box.type == 'i': info = self.getrawptrinfo(box) - return info.force_at_the_end_of_preamble(box, self.optearlyforce, - None) + if info is not None: + return info.force_at_the_end_of_preamble(box, + self.optearlyforce, None) return box def flush(self): diff --git a/rpython/jit/metainterp/test/test_virtual.py b/rpython/jit/metainterp/test/test_virtual.py --- a/rpython/jit/metainterp/test/test_virtual.py +++ b/rpython/jit/metainterp/test/test_virtual.py @@ -1234,7 +1234,7 @@ res = self.meta_interp(f, [10]) assert res == 55 self.check_trace_count(1) - self.check_resops(setarrayitem_raw=2, getarrayitem_raw=4) + self.check_resops(setarrayitem_raw=2, getarrayitem_raw_i=4) # ____________________________________________________________ # Run 1: all the tests instantiate a real RPython class From noreply at buildbot.pypy.org Thu Sep 3 20:31:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:31:00 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: write enough to pass the test, maybe we want to jump to preamble instead Message-ID: <20150903183100.CAC581C140E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79403:319cea2b97b0 Date: 2015-09-03 20:31 +0200 http://bitbucket.org/pypy/pypy/changeset/319cea2b97b0/ Log: write enough to pass the test, maybe we want to jump to preamble instead diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -339,8 +339,7 @@ loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: - raise Exception("think about it") - xxx + return None # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token.target_tokens[0]) @@ -1004,13 +1003,9 @@ # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. - #new_trace = create_empty_loop(metainterp) - #new_trace.inputargs = metainterp.history.inputargs[:] - - #new_trace.operations = metainterp.history.operations[:] + metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd - state = jitdriver_sd.warmstate if isinstance(resumekey, ResumeAtPositionDescr): inline_short_preamble = False else: diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -9,7 +9,7 @@ Optimization, LoopInfo, MININT, MAXINT from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo from rpython.jit.metainterp.optimizeopt.virtualstate import ( - VirtualStateConstructor, VirtualStatesCantMatch) + VirtualStateConstructor, VirtualStatesCantMatch, BadVirtualState) from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp from rpython.jit.metainterp import compile from rpython.rlib.debug import debug_print @@ -142,11 +142,14 @@ state.virtual_state, celltoken.target_tokens) # force the boxes for virtual state to match - args = target_virtual_state.make_inputargs( - [self.get_box_replacement(x) for x in end_jump.getarglist()], - self.optimizer, force_boxes=True) - for arg in args: - self.optimizer.force_box(arg) + try: + args = target_virtual_state.make_inputargs( + [self.get_box_replacement(x) for x in end_jump.getarglist()], + self.optimizer, force_boxes=True) + for arg in args: + self.optimizer.force_box(arg) + except BadVirtualState: + raise InvalidLoop extra_same_as = self.short_preamble_producer.extra_same_as[:] target_token = self.finalize_short_preamble(label_op, state.virtual_state) From noreply at buildbot.pypy.org Thu Sep 3 20:37:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 3 Sep 2015 20:37:43 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: add xxx here so we don't forget Message-ID: <20150903183743.AE8711C140E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79404:df099789d647 Date: 2015-09-03 20:37 +0200 http://bitbucket.org/pypy/pypy/changeset/df099789d647/ Log: add xxx here so we don't forget diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -339,11 +339,13 @@ loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: - return None + xxxx # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token.target_tokens[0]) - loop_data = SimpleCompileData(end_label, [jump_op], call_pure_results, + loop_data = SimpleCompileData(end_label, + [jump_op], + call_pure_results, enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, @@ -352,8 +354,9 @@ return None loop = partial_trace loop.original_jitcell_token = loop_jitcell_token - loop.operations = loop_ops[:] - loop.inputargs = loop_info.inputargs[:] + import pdb + pdb.set_trace() + loop.operations = loop.operations + loop_ops[:] loop.check_consistency() else: From noreply at buildbot.pypy.org Fri Sep 4 08:21:55 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 08:21:55 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: PPC Backend #2: test_runner.py is now "3/4rd passing". Message-ID: <20150904062155.533B51C14C3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79405:733ec999d18b Date: 2015-08-29 13:51 +0200 http://bitbucket.org/pypy/pypy/changeset/733ec999d18b/ Log: PPC Backend #2: test_runner.py is now "3/4rd passing". Various fixes. Also, optimized "prepare_int_lt" and other similar operations: before, a "int_lt; guard_true" combination was produced as highly inefficient assembler. And, the way we built "guard_xyz" operations would fail if the target of the branch is too far away (>32k); test and fix for this case. diff too long, truncating to 2000 out of 3139 lines diff --git a/rpython/jit/backend/ppc/TODO b/rpython/jit/backend/ppc/TODO deleted file mode 100644 --- a/rpython/jit/backend/ppc/TODO +++ /dev/null @@ -1,4 +0,0 @@ - -prepare_guard_int_lt & friends: re-enable in walk_operations() - -guard_xyz: fail if the target of the branch is too far away (+32k?) diff --git a/rpython/jit/backend/ppc/callbuilder.py b/rpython/jit/backend/ppc/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/ppc/callbuilder.py @@ -0,0 +1,60 @@ +from rpython.jit.backend.ppc.arch import IS_PPC_64, WORD +import rpython.jit.backend.ppc.register as r +from rpython.jit.metainterp.history import INT +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.ppc.jump import remap_frame_layout + + +def follow_jump(addr): + # xxx implement me + return addr + + +class CallBuilder(AbstractCallBuilder): + + def __init__(self, assembler, fnloc, arglocs, resloc): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype=INT, ressize=None) + + def prepare_arguments(self): + assert IS_PPC_64 + + # First, copy fnloc into r2 + self.asm.regalloc_mov(self.fnloc, r.r2) + + # Prepare arguments + arglocs = self.arglocs + argtypes = self.argtypes + + assert len(argtypes) <= 8, "XXX" + non_float_locs = arglocs + non_float_regs = ( # XXX + [r.r3, r.r4, r.r5, r.r6, r.r7, r.r8, r.r9, r.r10][:len(argtypes)]) + + remap_frame_layout(self.asm, non_float_locs, non_float_regs, + r.SCRATCH) + + + def push_gcmap(self): + pass # XXX + + def pop_gcmap(self): + pass # XXX + + def emit_raw_call(self): + # Load the function descriptor (currently in r2) from memory: + # [r2 + 0] -> ctr + # [r2 + 16] -> r11 + # [r2 + 8] -> r2 (= TOC) + self.mc.ld(r.SCRATCH.value, r.r2.value, 0) + self.mc.ld(r.r11.value, r.r2.value, 16) + self.mc.mtctr(r.SCRATCH.value) + self.mc.ld(r.TOC.value, r.r2.value, 8) + # Call it + self.mc.bctrl() + + def restore_stack_pointer(self): + pass # XXX + + def load_result(self): + pass diff --git a/rpython/jit/backend/ppc/codebuilder.py b/rpython/jit/backend/ppc/codebuilder.py --- a/rpython/jit/backend/ppc/codebuilder.py +++ b/rpython/jit/backend/ppc/codebuilder.py @@ -643,7 +643,7 @@ bdnz = BA.bc(BO=16, BI=0) bdnzt = BA.bc(BO=8) bdnzf = BA.bc(BO=0) - bdz = BA.bc(BO=18) + bdz = BA.bc(BO=18, BI=0) bdzt = BA.bc(BO=10) bdzf = BA.bc(BO=2) @@ -652,7 +652,7 @@ bdnza = BA.bca(BO=16, BI=0) bdnzta = BA.bca(BO=8) bdnzfa = BA.bca(BO=0) - bdza = BA.bca(BO=18) + bdza = BA.bca(BO=18, BI=0) bdzta = BA.bca(BO=10) bdzfa = BA.bca(BO=2) @@ -661,7 +661,7 @@ bdnzl = BA.bcl(BO=16, BI=0) bdnztl = BA.bcl(BO=8) bdnzfl = BA.bcl(BO=0) - bdzl = BA.bcl(BO=18) + bdzl = BA.bcl(BO=18, BI=0) bdztl = BA.bcl(BO=10) bdzfl = BA.bcl(BO=2) @@ -670,7 +670,7 @@ bdnzla = BA.bcla(BO=16, BI=0) bdnztla = BA.bcla(BO=8) bdnzfla = BA.bcla(BO=0) - bdzla = BA.bcla(BO=18) + bdzla = BA.bcla(BO=18, BI=0) bdztla = BA.bcla(BO=10) bdzfla = BA.bcla(BO=2) @@ -934,20 +934,24 @@ #self.offset = offset class OverwritingBuilder(PPCAssembler): - def __init__(self, cb, start, num_insts): + def __init__(self, mc, start, num_insts=0): PPCAssembler.__init__(self) - self.cb = cb + self.mc = mc self.index = start - self.num_insts = num_insts def currpos(self): assert 0, "not implemented" + def write32(self, word): + index = self.index + self.mc.overwrite(index, chr((word >> 24) & 0xff)) + self.mc.overwrite(index + 1, chr((word >> 16) & 0xff)) + self.mc.overwrite(index + 2, chr((word >> 8) & 0xff)) + self.mc.overwrite(index + 3, chr(word & 0xff)) + self.index = index + 4 + def overwrite(self): - assert len(self.insts) <= self.num_insts - startindex = self.index / 4 - for i, new_inst in enumerate(self.insts): - self.cb.insts[i + startindex] = new_inst + pass class PPCBuilder(BlockBuilderMixin, PPCAssembler): def __init__(self): @@ -997,16 +1001,16 @@ self.b(offset) def b_cond_offset(self, offset, condition): - BI = condition[0] - BO = condition[1] + assert condition != c.UH + BI, BO = c.encoding[condition] pos = self.currpos() target_ofs = offset - pos self.bc(BO, BI, target_ofs) def b_cond_abs(self, addr, condition): - BI = condition[0] - BO = condition[1] + assert condition != c.UH + BI, BO = c.encoding[condition] with scratch_reg(self): self.load_imm(r.SCRATCH, addr) diff --git a/rpython/jit/backend/ppc/condition.py b/rpython/jit/backend/ppc/condition.py --- a/rpython/jit/backend/ppc/condition.py +++ b/rpython/jit/backend/ppc/condition.py @@ -1,22 +1,32 @@ -# CONDITION = (BI (number of bit tested in CR), BO (12 if bit is 1, else 4)) +EQ = 0 +NE = 1 +LE = 2 +GT = 3 +LT = 4 +GE = 5 +SO = 6 +NS = 7 +UH = -1 # invalid -SET = 12 -UNSET = 4 +def negate(cond): + return cond ^ 1 -LE = (1, UNSET) -NE = (2, UNSET) -GT = (1, SET) -LT = (0, SET) -EQ = (2, SET) -GE = (0, UNSET) -UH = (-1, -1) # invalid +assert negate(EQ) == NE +assert negate(NE) == EQ +assert negate(LE) == GT +assert negate(GT) == LE +assert negate(LT) == GE +assert negate(GE) == LT +assert negate(SO) == NS +assert negate(NS) == SO -# values below are random ... - -U_LT = 50 -U_LE = 60 -U_GT = 70 -U_GE = 80 - -IS_TRUE = 90 -IS_ZERO = 100 +encoding = [ + (2, 12), # EQ + (2, 4), # NE + (1, 4), # LE + (1, 12), # GT + (0, 12), # LT + (0, 4), # GE + (3, 12), # SO + (3, 4), # NS +] diff --git a/rpython/jit/backend/ppc/helper/assembler.py b/rpython/jit/backend/ppc/helper/assembler.py --- a/rpython/jit/backend/ppc/helper/assembler.py +++ b/rpython/jit/backend/ppc/helper/assembler.py @@ -2,53 +2,70 @@ from rpython.rlib.rarithmetic import intmask from rpython.jit.backend.ppc.arch import MAX_REG_PARAMS, IS_PPC_32, WORD from rpython.jit.metainterp.history import FLOAT +from rpython.jit.metainterp.resoperation import rop import rpython.jit.backend.ppc.register as r from rpython.rtyper.lltypesystem import rffi, lltype +def test_condition_for(condition, guard_op): + opnum = guard_op.getopnum() + if opnum == rop.GUARD_FALSE: + return condition + elif opnum == rop.GUARD_TRUE: + return c.negate(condition) + assert 0, opnum + +def do_emit_cmp_op(self, guard_op, arglocs, condition, signed, fp): + l0 = arglocs[0] + l1 = arglocs[1] + assert not l0.is_imm() + # do the comparison + self.mc.cmp_op(0, l0.value, l1.value, + imm=l1.is_imm(), signed=signed, fp=fp) + + # CR bits: + # 0: LT + # 1: GT + # 2: EQ + # 3: UNordered + + if fp: + # Support for NaNs: with LE or GE, if one of the operands is a + # NaN, we get CR=1,0,0,0 (unordered bit only). We're about to + # check "not GT" or "not LT", but in case of NaN we want to + # get the answer False. + if condition == c.LE: + self.mc.crnor(1, 1, 3) + condition = c.GT + elif condition == c.GE: + self.mc.crnor(0, 0, 3) + condition = c.LT + + if guard_op is None: + # After the comparison, place the result in a single bit of the CR + bit, invert = c.encoding[condition] + assert 0 <= bit <= 3 + if invert == 12: + pass + elif invert == 4: + self.mc.crnor(bit, bit, bit) + else: + assert 0 + + assert len(arglocs) == 3 + res = arglocs[2] + resval = res.value + # move the content of the CR to resval + self.mc.mfcr(resval) + # zero out everything except of the result + self.mc.rlwinm(resval, resval, 1 + bit, 31, 31) + else: + failargs = arglocs[2:] + fcond = test_condition_for(condition, guard_op) + self._emit_guard(guard_op, failargs, fcond) + def gen_emit_cmp_op(condition, signed=True, fp=False): - def f(self, op, arglocs, regalloc): - l0, l1, res = arglocs - # do the comparison - self.mc.cmp_op(0, l0.value, l1.value, - imm=l1.is_imm(), signed=signed, fp=fp) - # After the comparison, place the result - # in the first bit of the CR - if condition == c.LT or condition == c.U_LT: - self.mc.cror(0, 0, 0) - elif condition == c.LE or condition == c.U_LE: - self.mc.cror(0, 0, 2) - elif condition == c.EQ: - self.mc.cror(0, 2, 2) - elif condition == c.GE or condition == c.U_GE: - self.mc.cror(0, 1, 2) - elif condition == c.GT or condition == c.U_GT: - self.mc.cror(0, 1, 1) - elif condition == c.NE: - self.mc.crnor(0, 2, 2) - else: - assert 0, "condition not known" - - resval = res.value - # move the content of the CR to resval - self.mc.mfcr(resval) - # zero out everything except of the result - self.mc.rlwinm(resval, resval, 1, 31, 31) - return f - -def gen_emit_unary_cmp_op(condition): - def f(self, op, arglocs, regalloc): - reg, res = arglocs - - self.mc.cmp_op(0, reg.value, 0, imm=True) - if condition == c.IS_ZERO: - self.mc.cror(0, 2, 2) - elif condition == c.IS_TRUE: - self.mc.cror(0, 0, 1) - else: - assert 0, "condition not known" - - self.mc.mfcr(res.value) - self.mc.rlwinm(res.value, res.value, 1, 31, 31) + def f(self, op, guard_op, arglocs, regalloc): + do_emit_cmp_op(self, guard_op, arglocs, condition, signed, fp) return f def count_reg_args(args): diff --git a/rpython/jit/backend/ppc/helper/regalloc.py b/rpython/jit/backend/ppc/helper/regalloc.py --- a/rpython/jit/backend/ppc/helper/regalloc.py +++ b/rpython/jit/backend/ppc/helper/regalloc.py @@ -1,127 +1,97 @@ from rpython.jit.metainterp.history import ConstInt, Box, FLOAT +from rpython.jit.backend.ppc.locations import imm -IMM_SIZE = 2 ** 15 - 1 - -def check_imm_box(arg, size=IMM_SIZE, allow_zero=True): +def check_imm_box(arg, lower_bound=-2**15, upper_bound=2**15-1): if isinstance(arg, ConstInt): - return _check_imm_arg(arg.getint(), size, allow_zero) + i = arg.getint() + return lower_bound <= i <= upper_bound return False -def _check_imm_arg(arg, size=IMM_SIZE, allow_zero=True): - assert not isinstance(arg, ConstInt) - #if not we_are_translated(): - # if not isinstance(arg, int): - # import pdb; pdb.set_trace() - i = arg - if allow_zero: - lower_bound = i >= 0 - else: - lower_bound = i > 0 - return i <= size and lower_bound +def _check_imm_arg(i): + return (-2**15) <= i <= (2**15-1) -def prepare_cmp_op(): - def f(self, op): - boxes = op.getarglist() - arg0, arg1 = boxes - imm_a0 = check_imm_box(arg0) - imm_a1 = check_imm_box(arg1) - l0 = self._ensure_value_is_boxed(arg0, forbidden_vars=boxes) +def _prepare_cmp_op(signed): + lower_bound = -2**15 if signed else 0 + upper_bound = 2**15-1 if signed else 2**16-1 + def f(self, op, guard_op): + l0 = self.ensure_reg(op.getarg(0)) + a1 = op.getarg(1) + if check_imm_box(a1, lower_bound, upper_bound): + l1 = imm(a1.getint()) + else: + l1 = self.ensure_reg(a1) + self.free_op_vars() + if guard_op is None: + res = self.force_allocate_reg(op.result) + return [l0, l1, res] + else: + return self._prepare_guard(guard_op, [l0, l1]) + return f +prepare_cmp_op = _prepare_cmp_op(signed=True) +prepare_cmp_op_unsigned = _prepare_cmp_op(signed=False) - if imm_a1 and not imm_a0: - l1 = self._ensure_value_is_boxed(arg1, boxes) - else: - l1 = self._ensure_value_is_boxed(arg1, forbidden_vars=boxes) - - self.possibly_free_vars_for_op(op) - self.free_temp_vars() +def prepare_unary_cmp(self, op, guard_op): + l0 = self.ensure_reg(op.getarg(0)) + l1 = imm(0) + self.free_op_vars() + if guard_op is None: res = self.force_allocate_reg(op.result) return [l0, l1, res] - return f + else: + return self._prepare_guard(guard_op, [l0, l1]) -def prepare_unary_cmp(): - def f(self, op): - a0 = op.getarg(0) - assert isinstance(a0, Box) - reg = self._ensure_value_is_boxed(a0) - self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg(op.result, [a0]) - return [reg, res] - return f +def prepare_float_cmp(self, op, guard_op): + l0 = self.ensure_reg(op.getarg(0)) + l1 = self.ensure_reg(op.getarg(1)) + self.free_op_vars() + if guard_op is None: + res = self.force_allocate_reg(op.result) + return [l0, l1, res] + else: + return self._prepare_guard(guard_op, [l0, l1]) -def prepare_unary_int_op(): - def f(self, op): - l0 = self._ensure_value_is_boxed(op.getarg(0)) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - return [l0, res] - return f +def prepare_unary_op(self, op): + l0 = self.ensure_reg(op.getarg(0)) + self.free_op_vars() + res = self.force_allocate_reg(op.result) + return [l0, res] -def prepare_binary_int_op_with_imm(): - def f(self, op): - a0 = op.getarg(0) - a1 = op.getarg(1) - boxes = op.getarglist() - l0 = self._ensure_value_is_boxed(a0, boxes) - if isinstance(a1, ConstInt) and _check_imm_arg(a1.getint()): - l1 = self.convert_to_imm(a1) - else: - l1 = self._ensure_value_is_boxed(a1, boxes) - locs = [l0, l1] - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - return locs + [res] - return f +def prepare_binary_op(self, op): + reg1 = self.ensure_reg(op.getarg(0)) + reg2 = self.ensure_reg(op.getarg(1)) + self.free_op_vars() + res = self.force_allocate_reg(op.result) + return [reg1, reg2, res] -def prepare_binary_int_op(): - def f(self, op): - boxes = op.getarglist() - b0, b1 = boxes +def prepare_int_add_or_mul(self, op): + a0 = op.getarg(0) + a1 = op.getarg(1) + if check_imm_box(a0): + a0, a1 = a1, a0 + l0 = self.ensure_reg(a0) + if check_imm_box(a1): + l1 = imm(a1.getint()) + else: + l1 = self.ensure_reg(a1) + self.free_op_vars() + res = self.force_allocate_reg(op.result) + return [l0, l1, res] - reg1 = self._ensure_value_is_boxed(b0, forbidden_vars=boxes) - reg2 = self._ensure_value_is_boxed(b1, forbidden_vars=boxes) +def prepare_int_sub(self, op): + l0 = self.ensure_reg(op.getarg(0)) + a1 = op.getarg(1) + if check_imm_box(a1, -2**15+1, 2**15): + l1 = imm(a1.getint()) + else: + l1 = self.ensure_reg(a1) + self.free_op_vars() + res = self.force_allocate_reg(op.result) + return [l0, l1, res] - self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) - return [reg1, reg2, res] - return f - -def prepare_float_op(name=None, base=True, float_result=True, guard=False): - if guard: - def f(self, op, guard_op): - locs = [] - loc1 = self._ensure_value_is_boxed(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self._ensure_value_is_boxed(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - else: - args = self._prepare_guard(guard_op, locs) - return args - else: - def f(self, op): - locs = [] - loc1 = self._ensure_value_is_boxed(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self._ensure_value_is_boxed(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - if name: - f.__name__ = name - return f - +def prepare_int_binary_ovf(self, op, guard_op): + reg1 = self.ensure_reg(op.getarg(0)) + reg2 = self.ensure_reg(op.getarg(1)) + self.free_op_vars() + res = self.force_allocate_reg(op.result) + assert guard_op is not None + return self._prepare_guard(guard_op, [reg1, reg2, res]) diff --git a/rpython/jit/backend/ppc/locations.py b/rpython/jit/backend/ppc/locations.py --- a/rpython/jit/backend/ppc/locations.py +++ b/rpython/jit/backend/ppc/locations.py @@ -24,6 +24,9 @@ def is_reg(self): return False + def is_core_reg(self): # for llsupport/assembler.py + return self.is_reg() + def is_fp_reg(self): return False diff --git a/rpython/jit/backend/ppc/opassembler.py b/rpython/jit/backend/ppc/opassembler.py --- a/rpython/jit/backend/ppc/opassembler.py +++ b/rpython/jit/backend/ppc/opassembler.py @@ -1,11 +1,10 @@ -from rpython.jit.backend.ppc.helper.assembler import (gen_emit_cmp_op, - gen_emit_unary_cmp_op) +from rpython.jit.backend.ppc.helper.assembler import gen_emit_cmp_op from rpython.jit.backend.ppc.helper.regalloc import _check_imm_arg import rpython.jit.backend.ppc.condition as c import rpython.jit.backend.ppc.register as r from rpython.jit.backend.ppc.locations import imm from rpython.jit.backend.ppc.locations import imm as make_imm_loc -from rpython.jit.backend.ppc.arch import (IS_PPC_32, WORD, +from rpython.jit.backend.ppc.arch import (IS_PPC_32, IS_PPC_64, WORD, MAX_REG_PARAMS, MAX_FREG_PARAMS) from rpython.jit.metainterp.history import (JitCellToken, TargetToken, Box, @@ -17,12 +16,11 @@ PPCBuilder, PPCGuardToken) from rpython.jit.backend.ppc.regalloc import TempPtr, TempInt from rpython.jit.backend.llsupport import symbolic -from rpython.jit.backend.llsupport.descr import InteriorFieldDescr +from rpython.jit.backend.llsupport.descr import InteriorFieldDescr, CallDescr from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.jit.metainterp.resoperation import rop - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.ppc import callbuilder class IntOpAssembler(object): @@ -30,47 +28,58 @@ def emit_int_add(self, op, arglocs, regalloc): l0, l1, res = arglocs - if l0.is_imm(): - self.mc.addi(res.value, l1.value, l0.value) - elif l1.is_imm(): + assert not l0.is_imm() + if l1.is_imm(): self.mc.addi(res.value, l0.value, l1.value) else: self.mc.add(res.value, l0.value, l1.value) - def emit_int_add_ovf(self, op, arglocs, regalloc): - l0, l1, res = arglocs - self.mc.addo(res.value, l0.value, l1.value) - def emit_int_sub(self, op, arglocs, regalloc): l0, l1, res = arglocs - if l0.is_imm(): - self.mc.subfic(res.value, l1.value, l0.value) - elif l1.is_imm(): + assert not l0.is_imm() + if l1.is_imm(): self.mc.subi(res.value, l0.value, l1.value) else: self.mc.sub(res.value, l0.value, l1.value) - def emit_int_sub_ovf(self, op, arglocs, regalloc): - l0, l1, res = arglocs - self.mc.subfo(res.value, l1.value, l0.value) - def emit_int_mul(self, op, arglocs, regalloc): l0, l1, res = arglocs - if l0.is_imm(): - self.mc.mulli(res.value, l1.value, l0.value) - elif l1.is_imm(): + assert not l0.is_imm() + if l1.is_imm(): self.mc.mulli(res.value, l0.value, l1.value) elif IS_PPC_32: self.mc.mullw(res.value, l0.value, l1.value) else: self.mc.mulld(res.value, l0.value, l1.value) - def emit_int_mul_ovf(self, op, arglocs, regalloc): - l0, l1, res = arglocs + def do_emit_int_binary_ovf(self, op, guard_op, arglocs, emit): + l0, l1, res = arglocs[0], arglocs[1], arglocs[2] + self.mc.load_imm(r.SCRATCH, 0) + self.mc.mtxer(r.SCRATCH.value) + emit(res.value, l0.value, l1.value) + # + failargs = arglocs[3:] + assert guard_op is not None + opnum = guard_op.getopnum() + if opnum == rop.GUARD_NO_OVERFLOW: + fcond = c.SO + elif opnum == rop.GUARD_OVERFLOW: + fcond = c.NS + else: + assert 0 + self._emit_guard(guard_op, failargs, fcond) + + def emit_guard_int_add_ovf(self, op, guard_op, arglocs, regalloc): + self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.addox) + + def emit_guard_int_sub_ovf(self, op, guard_op, arglocs, regalloc): + self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.subox) + + def emit_guard_int_mul_ovf(self, op, guard_op, arglocs, regalloc): if IS_PPC_32: - self.mc.mullwo(res.value, l0.value, l1.value) + self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.mullwox) else: - self.mc.mulldo(res.value, l0.value, l1.value) + self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.mulldox) def emit_int_floordiv(self, op, arglocs, regalloc): l0, l1, res = arglocs @@ -130,26 +139,26 @@ else: self.mc.divdu(res.value, l0.value, l1.value) - emit_int_le = gen_emit_cmp_op(c.LE) - emit_int_lt = gen_emit_cmp_op(c.LT) - emit_int_gt = gen_emit_cmp_op(c.GT) - emit_int_ge = gen_emit_cmp_op(c.GE) - emit_int_eq = gen_emit_cmp_op(c.EQ) - emit_int_ne = gen_emit_cmp_op(c.NE) + emit_guard_int_le = gen_emit_cmp_op(c.LE) + emit_guard_int_lt = gen_emit_cmp_op(c.LT) + emit_guard_int_gt = gen_emit_cmp_op(c.GT) + emit_guard_int_ge = gen_emit_cmp_op(c.GE) + emit_guard_int_eq = gen_emit_cmp_op(c.EQ) + emit_guard_int_ne = gen_emit_cmp_op(c.NE) - emit_uint_lt = gen_emit_cmp_op(c.U_LT, signed=False) - emit_uint_le = gen_emit_cmp_op(c.U_LE, signed=False) - emit_uint_gt = gen_emit_cmp_op(c.U_GT, signed=False) - emit_uint_ge = gen_emit_cmp_op(c.U_GE, signed=False) + emit_guard_uint_lt = gen_emit_cmp_op(c.LT, signed=False) + emit_guard_uint_le = gen_emit_cmp_op(c.LE, signed=False) + emit_guard_uint_gt = gen_emit_cmp_op(c.GT, signed=False) + emit_guard_uint_ge = gen_emit_cmp_op(c.GE, signed=False) - emit_int_is_zero = gen_emit_unary_cmp_op(c.IS_ZERO) - emit_int_is_true = gen_emit_unary_cmp_op(c.IS_TRUE) + emit_guard_int_is_zero = emit_guard_int_eq # EQ to 0 + emit_guard_int_is_true = emit_guard_int_ne # NE to 0 - emit_ptr_eq = emit_int_eq - emit_ptr_ne = emit_int_ne + emit_guard_ptr_eq = emit_guard_int_eq + emit_guard_ptr_ne = emit_guard_int_ne - emit_instance_ptr_eq = emit_ptr_eq - emit_instance_ptr_ne = emit_ptr_ne + emit_guard_instance_ptr_eq = emit_guard_ptr_eq + emit_guard_instance_ptr_ne = emit_guard_ptr_ne def emit_int_neg(self, op, arglocs, regalloc): l0, res = arglocs @@ -159,6 +168,18 @@ l0, res = arglocs self.mc.not_(res.value, l0.value) + def emit_int_signext(self, op, arglocs, regalloc): + l0, res = arglocs + extend_from = op.getarg(1).getint() + if extend_from == 1: + self.mc.extsb(res.value, l0.value) + elif extend_from == 2: + self.mc.extsh(res.value, l0.value) + elif extend_from == 4: + self.mc.extsw(res.value, l0.value) + else: + raise AssertionError(extend_from) + def emit_int_force_ge_zero(self, op, arglocs, regalloc): arg, res = arglocs with scratch_reg(self.mc): @@ -201,12 +222,12 @@ l0, res = arglocs self.mc.fsqrt(res.value, l0.value) - emit_float_le = gen_emit_cmp_op(c.LE, fp=True) - emit_float_lt = gen_emit_cmp_op(c.LT, fp=True) - emit_float_gt = gen_emit_cmp_op(c.GT, fp=True) - emit_float_ge = gen_emit_cmp_op(c.GE, fp=True) - emit_float_eq = gen_emit_cmp_op(c.EQ, fp=True) - emit_float_ne = gen_emit_cmp_op(c.NE, fp=True) + emit_guard_float_le = gen_emit_cmp_op(c.LE, fp=True) + emit_guard_float_lt = gen_emit_cmp_op(c.LT, fp=True) + emit_guard_float_gt = gen_emit_cmp_op(c.GT, fp=True) + emit_guard_float_ge = gen_emit_cmp_op(c.GE, fp=True) + emit_guard_float_eq = gen_emit_cmp_op(c.EQ, fp=True) + emit_guard_float_ne = gen_emit_cmp_op(c.NE, fp=True) def emit_cast_float_to_int(self, op, arglocs, regalloc): l0, temp_loc, res = arglocs @@ -215,10 +236,10 @@ self.mc.ld(res.value, r.SP.value, -16) def emit_cast_int_to_float(self, op, arglocs, regalloc): - l0, temp_loc, res = arglocs + l0, res = arglocs self.mc.std(l0.value, r.SP.value, -16) - self.mc.lfd(temp_loc.value, r.SP.value, -16) - self.mc.fcfid(res.value, temp_loc.value) + self.mc.lfd(res.value, r.SP.value, -16) + self.mc.fcfid(res.value, res.value) def emit_convert_float_bytes_to_longlong(self, op, arglocs, regalloc): l0, res = arglocs @@ -241,7 +262,8 @@ fcond, save_exc, is_guard_not_invalidated, is_guard_not_forced) token.pos_jump_offset = self.mc.currpos() - self.mc.nop() # has to be patched later on + if not is_guard_not_invalidated: + self.mc.trap() # has to be patched later on self.pending_guard_tokens.append(token) def build_guard_token(self, op, frame_depth, arglocs, fcond, save_exc, @@ -269,24 +291,6 @@ self.mc.cmp_op(0, l0.value, 0, imm=True) self._emit_guard(op, failargs, c.NE) - # TODO - Evaluate whether this can be done with - # SO bit instead of OV bit => usage of CR - # instead of XER could be more efficient - def _emit_ovf_guard(self, op, arglocs, cond): - # move content of XER to GPR - with scratch_reg(self.mc): - self.mc.mfspr(r.SCRATCH.value, 1) - # shift and mask to get comparison result - self.mc.rlwinm(r.SCRATCH.value, r.SCRATCH.value, 1, 0, 0) - self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - self._emit_guard(op, arglocs, cond) - - def emit_guard_no_overflow(self, op, arglocs, regalloc): - self._emit_ovf_guard(op, arglocs, c.NE) - - def emit_guard_overflow(self, op, arglocs, regalloc): - self._emit_ovf_guard(op, arglocs, c.EQ) - def emit_guard_value(self, op, arglocs, regalloc): l0 = arglocs[0] l1 = arglocs[1] @@ -307,15 +311,15 @@ def emit_guard_class(self, op, arglocs, regalloc): self._cmp_guard_class(op, arglocs, regalloc) - self._emit_guard(op, arglocs[3:], c.NE, save_exc=False) + self._emit_guard(op, arglocs[3:], c.NE) def emit_guard_nonnull_class(self, op, arglocs, regalloc): self.mc.cmp_op(0, arglocs[0].value, 1, imm=True, signed=False) patch_pos = self.mc.currpos() - self.mc.nop() + self.mc.trap() self._cmp_guard_class(op, arglocs, regalloc) pmc = OverwritingBuilder(self.mc, patch_pos, 1) - pmc.bc(12, 0, self.mc.currpos() - patch_pos) + pmc.bc(12, 0, self.mc.currpos() - patch_pos) # LT pmc.overwrite() self._emit_guard(op, arglocs[3:], c.NE, save_exc=False) @@ -330,7 +334,7 @@ # here, we have to go back from 'classptr' to the value expected # from reading the half-word in the object header. Note that # this half-word is at offset 0 on a little-endian machine; - # it would be at offset 2 (32 bit) or 4 (64 bit) on a + # but it is at offset 2 (32 bit) or 4 (64 bit) on a # big-endian machine. with scratch_reg(self.mc): if IS_PPC_32: @@ -340,7 +344,7 @@ self.mc.cmp_op(0, r.SCRATCH.value, typeid.value, imm=typeid.is_imm()) def emit_guard_not_invalidated(self, op, locs, regalloc): - return self._emit_guard(op, locs, c.EQ, is_guard_not_invalidated=True) + return self._emit_guard(op, locs, c.UH, is_guard_not_invalidated=True) class MiscOpAssembler(object): @@ -349,12 +353,12 @@ def emit_increment_debug_counter(self, op, arglocs, regalloc): [addr_loc, value_loc] = arglocs self.mc.load(value_loc.value, addr_loc.value, 0) - self.mc.addi(value_loc.value, value_loc.value, 1) + self.mc.addi(value_loc.value, value_loc.value, 1) # can't use r0! self.mc.store(value_loc.value, addr_loc.value, 0) def emit_finish(self, op, arglocs, regalloc): base_ofs = self.cpu.get_baseofs_of_frame_field() - if len(arglocs) == 2: + if len(arglocs) > 1: [return_val, fail_descr_loc] = arglocs if op.getarg(0).type == FLOAT: self.mc.stfd(return_val.value, r.SPP.value, base_ofs) @@ -409,7 +413,8 @@ def emit_same_as(self, op, arglocs, regalloc): argloc, resloc = arglocs - self.regalloc_mov(argloc, resloc) + if argloc is not resloc: + self.regalloc_mov(argloc, resloc) emit_cast_ptr_to_int = emit_same_as emit_cast_int_to_ptr = emit_same_as @@ -427,131 +432,129 @@ loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] failargs = arglocs[5:] self.mc.load_imm(loc1, pos_exception.value) - - with scratch_reg(self.mc): - self.mc.load(r.SCRATCH.value, loc1.value, 0) - self.mc.cmp_op(0, r.SCRATCH.value, loc.value) + self.mc.load(r.SCRATCH.value, loc1.value, 0) + self.mc.cmp_op(0, r.SCRATCH.value, loc.value) self._emit_guard(op, failargs, c.NE, save_exc=True) self.mc.load_imm(loc, pos_exc_value.value) if resloc: self.mc.load(resloc.value, loc.value, 0) + + self.mc.load_imm(r.SCRATCH, 0) + self.mc.store(r.SCRATCH.value, loc.value, 0) + self.mc.store(r.SCRATCH.value, loc1.value, 0) - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, 0) - self.mc.store(r.SCRATCH.value, loc.value, 0) - self.mc.store(r.SCRATCH.value, loc1.value, 0) - - def emit_call(self, op, arglocs, regalloc, force_index=NO_FORCE_INDEX): - if force_index == NO_FORCE_INDEX: - force_index = self.write_new_force_index() + def emit_call(self, op, arglocs, regalloc): resloc = arglocs[0] adr = arglocs[1] arglist = arglocs[2:] + + cb = callbuilder.CallBuilder(self, adr, arglist, resloc) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - self._emit_call(force_index, adr, arglist, resloc, (size, signed)) + assert isinstance(descr, CallDescr) + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() - def _emit_call(self, force_index, adr, arglocs, - result=None, result_info=(-1,-1)): - n_args = len(arglocs) + cb.emit() - # collect variables that need to go in registers - # and the registers they will be stored in - num = 0 - fpnum = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - float_stack_arg = False - for i in range(n_args): - arg = arglocs[i] + ## def _emit_call(self, adr, arglocs, result=None, result_info=(-1,-1)): + ## n_args = len(arglocs) - if arg.type == FLOAT: - if fpnum < MAX_FREG_PARAMS: - fpreg = r.PARAM_FPREGS[fpnum] - float_locs.append(arg) - float_regs.append(fpreg) - fpnum += 1 - # XXX Duplicate float arguments in GPR slots - if num < MAX_REG_PARAMS: - num += 1 - else: - stack_args.append(arg) - else: - stack_args.append(arg) - else: - if num < MAX_REG_PARAMS: - reg = r.PARAM_REGS[num] - non_float_locs.append(arg) - non_float_regs.append(reg) - num += 1 - else: - stack_args.append(arg) - float_stack_arg = True + ## # collect variables that need to go in registers + ## # and the registers they will be stored in + ## num = 0 + ## fpnum = 0 + ## count = 0 + ## non_float_locs = [] + ## non_float_regs = [] + ## float_locs = [] + ## float_regs = [] + ## stack_args = [] + ## float_stack_arg = False + ## for i in range(n_args): + ## arg = arglocs[i] - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r11) - adr = r.r11 + ## if arg.type == FLOAT: + ## if fpnum < MAX_FREG_PARAMS: + ## fpreg = r.PARAM_FPREGS[fpnum] + ## float_locs.append(arg) + ## float_regs.append(fpreg) + ## fpnum += 1 + ## # XXX Duplicate float arguments in GPR slots + ## if num < MAX_REG_PARAMS: + ## num += 1 + ## else: + ## stack_args.append(arg) + ## else: + ## stack_args.append(arg) + ## else: + ## if num < MAX_REG_PARAMS: + ## reg = r.PARAM_REGS[num] + ## non_float_locs.append(arg) + ## non_float_regs.append(reg) + ## num += 1 + ## else: + ## stack_args.append(arg) + ## float_stack_arg = True - # compute maximum of parameters passed - self.max_stack_params = max(self.max_stack_params, len(stack_args)) + ## if adr in non_float_regs: + ## non_float_locs.append(adr) + ## non_float_regs.append(r.r11) + ## adr = r.r11 - # compute offset at which parameters are stored - if IS_PPC_32: - param_offset = BACKCHAIN_SIZE * WORD - else: - # space for first 8 parameters - param_offset = ((BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) + ## # compute maximum of parameters passed + ## self.max_stack_params = max(self.max_stack_params, len(stack_args)) - with scratch_reg(self.mc): - if float_stack_arg: - self.mc.stfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) - for i, arg in enumerate(stack_args): - offset = param_offset + i * WORD - if arg is not None: - if arg.type == FLOAT: - self.regalloc_mov(arg, r.f0) - self.mc.stfd(r.f0.value, r.SP.value, offset) - else: - self.regalloc_mov(arg, r.SCRATCH) - self.mc.store(r.SCRATCH.value, r.SP.value, offset) - if float_stack_arg: - self.mc.lfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) + ## # compute offset at which parameters are stored + ## if IS_PPC_32: + ## param_offset = BACKCHAIN_SIZE * WORD + ## else: + ## # space for first 8 parameters + ## param_offset = ((BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) - # remap values stored in core registers - remap_frame_layout(self, float_locs, float_regs, r.f0) - remap_frame_layout(self, non_float_locs, non_float_regs, r.SCRATCH) + ## with scratch_reg(self.mc): + ## if float_stack_arg: + ## self.mc.stfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) + ## for i, arg in enumerate(stack_args): + ## offset = param_offset + i * WORD + ## if arg is not None: + ## if arg.type == FLOAT: + ## self.regalloc_mov(arg, r.f0) + ## self.mc.stfd(r.f0.value, r.SP.value, offset) + ## else: + ## self.regalloc_mov(arg, r.SCRATCH) + ## self.mc.store(r.SCRATCH.value, r.SP.value, offset) + ## if float_stack_arg: + ## self.mc.lfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) - # the actual call - if adr.is_imm(): - self.mc.call(adr.value) - elif adr.is_stack(): - self.regalloc_mov(adr, r.SCRATCH) - self.mc.call_register(r.SCRATCH) - elif adr.is_reg(): - self.mc.call_register(adr) - else: - assert 0, "should not reach here" + ## # remap values stored in core registers + ## remap_frame_layout(self, float_locs, float_regs, r.f0) + ## remap_frame_layout(self, non_float_locs, non_float_regs, r.SCRATCH) - self.mark_gc_roots(force_index) - # ensure the result is wellformed and stored in the correct location - if result is not None and result_info != (-1, -1): - self._ensure_result_bit_extension(result, result_info[0], - result_info[1]) + ## # the actual call + ## if adr.is_imm(): + ## self.mc.call(adr.value) + ## elif adr.is_stack(): + ## self.regalloc_mov(adr, r.SCRATCH) + ## self.mc.call_register(r.SCRATCH) + ## elif adr.is_reg(): + ## self.mc.call_register(adr) + ## else: + ## assert 0, "should not reach here" + + ## self.mark_gc_roots(force_index) + ## # ensure the result is wellformed and stored in the correct location + ## if result is not None and result_info != (-1, -1): + ## self._ensure_result_bit_extension(result, result_info[0], + ## result_info[1]) class FieldOpAssembler(object): _mixin_ = True - def emit_setfield_gc(self, op, arglocs, regalloc): - value_loc, base_loc, ofs, size = arglocs + def _write_to_mem(self, value_loc, base_loc, ofs, size): if size.value == 8: if value_loc.is_fp_reg(): if ofs.is_imm(): @@ -581,10 +584,17 @@ else: assert 0, "size not supported" + def emit_setfield_gc(self, op, arglocs, regalloc): + value_loc, base_loc, ofs, size = arglocs + self._write_to_mem(value_loc, base_loc, ofs, size) + emit_setfield_raw = emit_setfield_gc + emit_zero_ptr_field = emit_setfield_gc - def emit_getfield_gc(self, op, arglocs, regalloc): - base_loc, ofs, res, size = arglocs + def _load_from_mem(self, res, base_loc, ofs, size, signed): + # res, base_loc, ofs, size and signed are all locations + assert base_loc is not r.SCRATCH + sign = signed.value if size.value == 8: if res.is_fp_reg(): if ofs.is_imm(): @@ -597,261 +607,229 @@ else: self.mc.ldx(res.value, base_loc.value, ofs.value) elif size.value == 4: - if ofs.is_imm(): - self.mc.lwz(res.value, base_loc.value, ofs.value) + if IS_PPC_64 and sign: + if ofs.is_imm(): + self.mc.lwa(res.value, base_loc.value, ofs.value) + else: + self.mc.lwax(res.value, base_loc.value, ofs.value) else: - self.mc.lwzx(res.value, base_loc.value, ofs.value) + if ofs.is_imm(): + self.mc.lwz(res.value, base_loc.value, ofs.value) + else: + self.mc.lwzx(res.value, base_loc.value, ofs.value) elif size.value == 2: - if ofs.is_imm(): - self.mc.lhz(res.value, base_loc.value, ofs.value) + if sign: + if ofs.is_imm(): + self.mc.lha(res.value, base_loc.value, ofs.value) + else: + self.mc.lhax(res.value, base_loc.value, ofs.value) else: - self.mc.lhzx(res.value, base_loc.value, ofs.value) + if ofs.is_imm(): + self.mc.lhz(res.value, base_loc.value, ofs.value) + else: + self.mc.lhzx(res.value, base_loc.value, ofs.value) elif size.value == 1: if ofs.is_imm(): self.mc.lbz(res.value, base_loc.value, ofs.value) else: self.mc.lbzx(res.value, base_loc.value, ofs.value) + if sign: + self.mc.extsb(res.value, res.value) else: assert 0, "size not supported" - signed = op.getdescr().is_field_signed() - if signed: - self._ensure_result_bit_extension(res, size.value, signed) + def emit_getfield_gc(self, op, arglocs, regalloc): + base_loc, ofs, res, size, sign = arglocs + self._load_from_mem(res, base_loc, ofs, size, sign) emit_getfield_raw = emit_getfield_gc emit_getfield_raw_pure = emit_getfield_gc emit_getfield_gc_pure = emit_getfield_gc + SIZE2SCALE = dict([(1<<_i, _i) for _i in range(32)]) + + def _multiply_by_constant(self, loc, multiply_by, scratch_loc): + if multiply_by == 1: + return loc + try: + scale = self.SIZE2SCALE[multiply_by] + except KeyError: + if _check_imm_arg(multiply_by): + self.mc.mulli(scratch_loc.value, loc.value, multiply_by) + else: + self.mc.load_imm(scratch_loc.value, multiply_by) + if IS_PPC_32: + self.mc.mullw(scratch_loc.value, loc.value, + scratch_loc.value) + else: + self.mc.mulld(scratch_loc.value, loc.value, + scratch_loc.value) + else: + self.mc.sldi(scratch_loc.value, loc.value, scale) + return scratch_loc + + def _apply_scale(self, ofs, index_loc, itemsize): + # For arrayitem and interiorfield reads and writes: this returns an + # offset suitable for use in ld/ldx or similar instructions. + # The result will be either the register r2 or a 16-bit immediate. + # The arguments stand for "ofs + index_loc * itemsize", + # with the following constrains: + assert ofs.is_imm() # must be an immediate... + assert _check_imm_arg(ofs.getint()) # ...that fits 16 bits + assert index_loc is not r.SCRATCH2 # can be a reg or imm (any size) + assert itemsize.is_imm() # must be an immediate (any size) + + multiply_by = itemsize.value + offset = ofs.getint() + if index_loc.is_imm(): + offset += index_loc.getint() * multiply_by + if _check_imm_arg(offset): + return imm(offset) + else: + self.mc.load_imm(r.SCRATCH2, offset) + return r.SCRATCH2 + else: + index_loc = self._multiply_by_constant(index_loc, multiply_by, + r.SCRATCH2) + # here, the new index_loc contains 'index_loc * itemsize'. + # If offset != 0 then we have to add it here. Note that + # mc.addi() would not be valid with operand r0. + if offset != 0: + self.mc.addi(r.SCRATCH2.value, index_loc.value, offset) + index_loc = r.SCRATCH2 + return index_loc + def emit_getinteriorfield_gc(self, op, arglocs, regalloc): - (base_loc, index_loc, res_loc, - ofs_loc, ofs, itemsize, fieldsize) = arglocs - with scratch_reg(self.mc): - if _check_imm_arg(itemsize.value): - self.mc.mulli(r.SCRATCH.value, index_loc.value, itemsize.value) - else: - self.mc.load_imm(r.SCRATCH, itemsize.value) - self.mc.mullw(r.SCRATCH.value, index_loc.value, r.SCRATCH.value) - descr = op.getdescr() - assert isinstance(descr, InteriorFieldDescr) - signed = descr.fielddescr.is_field_signed() - if ofs.value > 0: - if ofs_loc.is_imm(): - self.mc.addic(r.SCRATCH.value, r.SCRATCH.value, ofs_loc.value) - else: - self.mc.add(r.SCRATCH.value, r.SCRATCH.value, ofs_loc.value) - - if fieldsize.value == 8: - if res_loc.is_fp_reg(): - self.mc.lfdx(res_loc.value, base_loc.value, r.SCRATCH.value) - else: - self.mc.ldx(res_loc.value, base_loc.value, r.SCRATCH.value) - elif fieldsize.value == 4: - self.mc.lwzx(res_loc.value, base_loc.value, r.SCRATCH.value) - if signed: - self.mc.extsw(res_loc.value, res_loc.value) - elif fieldsize.value == 2: - self.mc.lhzx(res_loc.value, base_loc.value, r.SCRATCH.value) - if signed: - self.mc.extsh(res_loc.value, res_loc.value) - elif fieldsize.value == 1: - self.mc.lbzx(res_loc.value, base_loc.value, r.SCRATCH.value) - if signed: - self.mc.extsb(res_loc.value, res_loc.value) - else: - assert 0 + (base_loc, index_loc, res_loc, ofs_loc, + itemsize, fieldsize, fieldsign) = arglocs + ofs_loc = self._apply_scale(ofs_loc, index_loc, itemsize) + self._load_from_mem(res_loc, base_loc, ofs_loc, fieldsize, fieldsign) emit_getinteriorfield_raw = emit_getinteriorfield_gc def emit_setinteriorfield_gc(self, op, arglocs, regalloc): - (base_loc, index_loc, value_loc, - ofs_loc, ofs, itemsize, fieldsize) = arglocs - with scratch_reg(self.mc): - if _check_imm_arg(itemsize.value): - self.mc.mulli(r.SCRATCH.value, index_loc.value, itemsize.value) - else: - self.mc.load_imm(r.SCRATCH, itemsize.value) - self.mc.mullw(r.SCRATCH.value, index_loc.value, r.SCRATCH.value) - if ofs.value > 0: - if ofs_loc.is_imm(): - self.mc.addic(r.SCRATCH.value, r.SCRATCH.value, ofs_loc.value) - else: - self.mc.add(r.SCRATCH.value, r.SCRATCH.value, ofs_loc.value) - if fieldsize.value == 8: - if value_loc.is_fp_reg(): - self.mc.stfdx(value_loc.value, base_loc.value, r.SCRATCH.value) - else: - self.mc.stdx(value_loc.value, base_loc.value, r.SCRATCH.value) - elif fieldsize.value == 4: - self.mc.stwx(value_loc.value, base_loc.value, r.SCRATCH.value) - elif fieldsize.value == 2: - self.mc.sthx(value_loc.value, base_loc.value, r.SCRATCH.value) - elif fieldsize.value == 1: - self.mc.stbx(value_loc.value, base_loc.value, r.SCRATCH.value) - else: - assert 0 + (base_loc, index_loc, value_loc, ofs_loc, + itemsize, fieldsize) = arglocs + ofs_loc = self._apply_scale(ofs_loc, index_loc, itemsize) + self._write_to_mem(value_loc, base_loc, ofs_loc, fieldsize) emit_setinteriorfield_raw = emit_setinteriorfield_gc -class ArrayOpAssembler(object): - - _mixin_ = True - def emit_arraylen_gc(self, op, arglocs, regalloc): res, base_loc, ofs = arglocs self.mc.load(res.value, base_loc.value, ofs.value) - def emit_setarrayitem_gc(self, op, arglocs, regalloc): - value_loc, base_loc, ofs_loc, scratch_loc, scale, ofs = arglocs - assert ofs_loc.is_reg() - - if scale.value > 0: - #scale_loc = r.SCRATCH - scale_loc = scratch_loc - if IS_PPC_32: - self.mc.slwi(scale_loc.value, ofs_loc.value, scale.value) - else: - self.mc.sldi(scale_loc.value, ofs_loc.value, scale.value) - else: - scale_loc = ofs_loc - - # add the base offset - if ofs.value > 0: - self.mc.addi(r.SCRATCH.value, scale_loc.value, ofs.value) - scale_loc = r.SCRATCH - - if scale.value == 3: - if value_loc.is_fp_reg(): - self.mc.stfdx(value_loc.value, base_loc.value, scale_loc.value) - else: - self.mc.stdx(value_loc.value, base_loc.value, scale_loc.value) - elif scale.value == 2: - self.mc.stwx(value_loc.value, base_loc.value, scale_loc.value) - elif scale.value == 1: - self.mc.sthx(value_loc.value, base_loc.value, scale_loc.value) - elif scale.value == 0: - self.mc.stbx(value_loc.value, base_loc.value, scale_loc.value) - else: - assert 0, "scale %s not supported" % (scale.value) - + emit_setarrayitem_gc = emit_setinteriorfield_gc emit_setarrayitem_raw = emit_setarrayitem_gc - def _write_to_mem(self, value_loc, base_loc, ofs_loc, scale): - if scale.value == 3: - if value_loc.is_fp_reg(): - self.mc.stfdx(value_loc.value, base_loc.value, ofs_loc.value) - else: - self.mc.stdx(value_loc.value, base_loc.value, ofs_loc.value) - elif scale.value == 2: - self.mc.stwx(value_loc.value, base_loc.value, ofs_loc.value) - elif scale.value == 1: - self.mc.sthx(value_loc.value, base_loc.value, ofs_loc.value) - elif scale.value == 0: - self.mc.stbx(value_loc.value, base_loc.value, ofs_loc.value) - else: - assert 0 - - def emit_raw_store(self, op, arglocs, regalloc): - value_loc, base_loc, ofs_loc, scale, ofs = arglocs - assert ofs_loc.is_reg() - self._write_to_mem(value_loc, base_loc, ofs_loc, scale) - - def emit_getarrayitem_gc(self, op, arglocs, regalloc): - res, base_loc, ofs_loc, scratch_loc, scale, ofs = arglocs - assert ofs_loc.is_reg() - signed = op.getdescr().is_item_signed() - - if scale.value > 0: - scale_loc = scratch_loc - if IS_PPC_32: - self.mc.slwi(scale_loc.value, ofs_loc.value, scale.value) - else: - self.mc.sldi(scale_loc.value, ofs_loc.value, scale.value) - else: - scale_loc = ofs_loc - - # add the base offset - if ofs.value > 0: - self.mc.addi(r.SCRATCH.value, scale_loc.value, ofs.value) - scale_loc = r.SCRATCH - - if scale.value == 3: - if res.is_fp_reg(): - self.mc.lfdx(res.value, base_loc.value, scale_loc.value) - else: - self.mc.ldx(res.value, base_loc.value, scale_loc.value) - elif scale.value == 2: - self.mc.lwzx(res.value, base_loc.value, scale_loc.value) - if signed: - self.mc.extsw(res.value, res.value) - elif scale.value == 1: - self.mc.lhzx(res.value, base_loc.value, scale_loc.value) - if signed: - self.mc.extsh(res.value, res.value) - elif scale.value == 0: - self.mc.lbzx(res.value, base_loc.value, scale_loc.value) - if signed: - self.mc.extsb(res.value, res.value) - else: - assert 0 - + emit_getarrayitem_gc = emit_getinteriorfield_gc emit_getarrayitem_raw = emit_getarrayitem_gc emit_getarrayitem_gc_pure = emit_getarrayitem_gc - def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale, signed=False): - if scale.value == 3: - if res_loc.is_fp_reg(): - self.mc.lfdx(res_loc.value, base_loc.value, ofs_loc.value) + emit_raw_store = emit_setarrayitem_gc + emit_raw_load = emit_getarrayitem_gc + + def _copy_in_scratch2(self, loc): + if loc.is_imm(): + self.mc.li(r.SCRATCH2.value, loc.value) + elif loc is not r.SCRATCH2: + self.mc.mr(r.SCRATCH2.value, loc.value) + return r.SCRATCH2 + + def emit_zero_array(self, op, arglocs, regalloc): + base_loc, startindex_loc, length_loc, ofs_loc, itemsize_loc = arglocs + + # assume that an array where an item size is N: + # * if N is even, then all items are aligned to a multiple of 2 + # * if N % 4 == 0, then all items are aligned to a multiple of 4 + # * if N % 8 == 0, then all items are aligned to a multiple of 8 + itemsize = itemsize_loc.getint() + if itemsize & 1: + stepsize = 1 + stXux = self.mc.stbux + stXu = self.mc.stbu + stX = self.mc.stb + elif itemsize & 2: + stepsize = 2 + stXux = self.mc.sthux + stXu = self.mc.sthu + stX = self.mc.sth + elif (itemsize & 4) or IS_PPC_32: + stepsize = 4 + stXux = self.mc.stwux + stXu = self.mc.stwu + stX = self.mc.stw + else: + stepsize = WORD + stXux = self.mc.stdux + stXu = self.mc.stdu + stX = self.mc.std + + repeat_factor = itemsize // stepsize + if repeat_factor != 1: + # This is only for itemsize not in (1, 2, 4, WORD). + # Include the repeat_factor inside length_loc if it is a constant + if length_loc.is_imm(): + length_loc = imm(length_loc.value * repeat_factor) + repeat_factor = 1 # included + + unroll = -1 + if length_loc.is_imm(): + if length_loc.value <= 8: + unroll = length_loc.value + if unroll <= 0: + return # nothing to do + + ofs_loc = self._apply_scale(ofs_loc, startindex_loc, itemsize_loc) + ofs_loc = self._copy_in_scratch2(ofs_loc) + + if unroll > 0: + assert repeat_factor == 1 + self.mc.li(r.SCRATCH.value, 0) + stXux(r.SCRATCH.value, ofs_loc.value, base_loc.value) + for i in range(1, unroll): + stX(r.SCRATCH.value, ofs_loc.value, i * stepsize) + + else: + if length_loc.is_imm(): + self.mc.load_imm(r.SCRATCH, length_loc.value) + length_loc = r.SCRATCH + jz_location = -1 + assert repeat_factor == 1 else: - self.mc.ldx(res_loc.value, base_loc.value, ofs_loc.value) - elif scale.value == 2: - self.mc.lwzx(res_loc.value, base_loc.value, ofs_loc.value) - if signed: - self.mc.extsw(res_loc.value, res_loc.value) - elif scale.value == 1: - self.mc.lhzx(res_loc.value, base_loc.value, ofs_loc.value) - if signed: - self.mc.extsh(res_loc.value, res_loc.value) - elif scale.value == 0: - self.mc.lbzx(res_loc.value, base_loc.value, ofs_loc.value) - if signed: - self.mc.extsb(res_loc.value, res_loc.value) - else: - assert 0 + self.mc.cmp_op(0, length_loc.value, 0, imm=True) + jz_location = self.mc.currpos() + self.mc.trap() + length_loc = self._multiply_by_constant(length_loc, + repeat_factor, + r.SCRATCH) + self.mc.mtctr(length_loc.value) + self.mc.li(r.SCRATCH.value, 0) - def emit_raw_load(self, op, arglocs, regalloc): - res_loc, base_loc, ofs_loc, scale, ofs = arglocs - assert ofs_loc.is_reg() - # no base offset - assert ofs.value == 0 - signed = op.getdescr().is_item_signed() - self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed) + stXux(r.SCRATCH.value, ofs_loc.value, base_loc.value) + bdz_location = self.mc.currpos() + self.mc.trap() + + loop_location = self.mc.currpos() + stXu(r.SCRATCH.value, ofs_loc.value, stepsize) + self.mc.bdnz(loop_location - self.mc.currpos()) + + pmc = OverwritingBuilder(self.mc, bdz_location, 1) + pmc.bdz(self.mc.currpos() - bdz_location) + pmc.overwrite() + + if jz_location != -1: + pmc = OverwritingBuilder(self.mc, jz_location, 1) + pmc.bc(4, 1, self.mc.currpos() - jz_location) # !GT + pmc.overwrite() class StrOpAssembler(object): _mixin_ = True - def emit_strlen(self, op, arglocs, regalloc): - l0, l1, res = arglocs - if l1.is_imm(): - self.mc.load(res.value, l0.value, l1.getint()) - else: - self.mc.loadx(res.value, l0.value, l1.value) - - def emit_strgetitem(self, op, arglocs, regalloc): - res, base_loc, ofs_loc, basesize = arglocs - if ofs_loc.is_imm(): - self.mc.addi(res.value, base_loc.value, ofs_loc.getint()) - else: - self.mc.add(res.value, base_loc.value, ofs_loc.value) - self.mc.lbz(res.value, res.value, basesize.value) - - def emit_strsetitem(self, op, arglocs, regalloc): - value_loc, base_loc, ofs_loc, temp_loc, basesize = arglocs - if ofs_loc.is_imm(): - self.mc.addi(temp_loc.value, base_loc.value, ofs_loc.getint()) - else: - self.mc.add(temp_loc.value, base_loc.value, ofs_loc.value) - self.mc.stb(value_loc.value, temp_loc.value, basesize.value) + emit_strlen = FieldOpAssembler.emit_getfield_gc + emit_strgetitem = FieldOpAssembler.emit_getarrayitem_gc + emit_strsetitem = FieldOpAssembler.emit_setarrayitem_gc #from ../x86/regalloc.py:928 ff. def emit_copystrcontent(self, op, arglocs, regalloc): @@ -901,6 +879,7 @@ else: length_box = TempInt() length_loc = regalloc.force_allocate_reg(length_box, forbidden_vars) + xxxxxxxxxxxxxxxxxxxxxxxx imm = regalloc.convert_to_imm(args[4]) self.load(length_loc, imm) if is_unicode: @@ -919,7 +898,7 @@ # call memcpy() regalloc.before_call() imm_addr = make_imm_loc(self.memcpy_addr) - self._emit_call(NO_FORCE_INDEX, imm_addr, + self._emit_call(imm_addr, [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.possibly_free_var(length_box) @@ -970,41 +949,9 @@ _mixin_ = True - emit_unicodelen = StrOpAssembler.emit_strlen - - def emit_unicodegetitem(self, op, arglocs, regalloc): - # res is used as a temporary location - # => it is save to use it before loading the result - res, base_loc, ofs_loc, scale, basesize, itemsize = arglocs - - if IS_PPC_32: - self.mc.slwi(res.value, ofs_loc.value, scale.value) - else: - self.mc.sldi(res.value, ofs_loc.value, scale.value) - self.mc.add(res.value, base_loc.value, res.value) - - if scale.value == 2: - self.mc.lwz(res.value, res.value, basesize.value) - elif scale.value == 1: - self.mc.lhz(res.value, res.value, basesize.value) - else: - assert 0, itemsize.value - - def emit_unicodesetitem(self, op, arglocs, regalloc): - value_loc, base_loc, ofs_loc, temp_loc, scale, basesize, itemsize = arglocs - - if IS_PPC_32: - self.mc.slwi(temp_loc.value, ofs_loc.value, scale.value) - else: - self.mc.sldi(temp_loc.value, ofs_loc.value, scale.value) - self.mc.add(temp_loc.value, base_loc.value, temp_loc.value) - - if scale.value == 2: - self.mc.stw(value_loc.value, temp_loc.value, basesize.value) - elif scale.value == 1: - self.mc.sth(value_loc.value, temp_loc.value, basesize.value) - else: - assert 0, itemsize.value + emit_unicodelen = FieldOpAssembler.emit_getfield_gc + emit_unicodegetitem = FieldOpAssembler.emit_getarrayitem_gc + emit_unicodesetitem = FieldOpAssembler.emit_setarrayitem_gc class AllocOpAssembler(object): @@ -1169,7 +1116,6 @@ def emit_force_token(self, op, arglocs, regalloc): res_loc = arglocs[0] self.mc.mr(res_loc.value, r.SPP.value) - self.mc.addi(res_loc.value, res_loc.value, FORCE_INDEX_OFS) # self._emit_guard(guard_op, regalloc._prepare_guard(guard_op), c.LT) # from: ../x86/assembler.py:1668 @@ -1186,6 +1132,7 @@ assert isinstance(descr, JitCellToken) # check value assert tmploc is r.RES + xxxxxxxxxxxx self._emit_call(fail_index, imm(descr._ppc_func_addr), callargs, result=tmploc) if op.result is None: @@ -1320,6 +1267,7 @@ size = descr.get_result_size() signed = descr.is_result_signed() # + xxxxxxxxxxxxxx self._emit_call(fail_index, adr, callargs, resloc, (size, signed)) with scratch_reg(self.mc): @@ -1348,6 +1296,7 @@ size = descr.get_result_size() signed = descr.is_result_signed() # + xxxxxxxxxxxxxxx self._emit_call(fail_index, adr, callargs, resloc, (size, signed)) # then reopen the stack if gcrootmap: @@ -1366,7 +1315,7 @@ with Saved_Volatiles(self.mc): #self._emit_call(NO_FORCE_INDEX, self.releasegil_addr, # [], self._regalloc) - self._emit_call(NO_FORCE_INDEX, imm(self.releasegil_addr), []) + self._emit_call(imm(self.releasegil_addr), []) def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result into the stack temporarily. @@ -1374,12 +1323,12 @@ # to save vfp regs in this case. Besides the result location assert gcrootmap.is_shadow_stack with Saved_Volatiles(self.mc): - self._emit_call(NO_FORCE_INDEX, imm(self.reacqgil_addr), []) + self._emit_call(imm(self.reacqgil_addr), []) class OpAssembler(IntOpAssembler, GuardOpAssembler, MiscOpAssembler, FieldOpAssembler, - ArrayOpAssembler, StrOpAssembler, + StrOpAssembler, UnicodeOpAssembler, ForceOpAssembler, AllocOpAssembler, FloatOpAssembler): diff --git a/rpython/jit/backend/ppc/ppc_assembler.py b/rpython/jit/backend/ppc/ppc_assembler.py --- a/rpython/jit/backend/ppc/ppc_assembler.py +++ b/rpython/jit/backend/ppc/ppc_assembler.py @@ -224,14 +224,18 @@ self._push_all_regs_to_jitframe(mc, [], withfloats) if exc: - # We might have an exception pending. Load it into r2... - mc.write32(0) - #mc.MOV(ebx, heap(self.cpu.pos_exc_value())) - #mc.MOV(heap(self.cpu.pos_exception()), imm0) - #mc.MOV(heap(self.cpu.pos_exc_value()), imm0) - ## ...and save ebx into 'jf_guard_exc' - #offset = self.cpu.get_ofs_of_frame_field('jf_guard_exc') - #mc.MOV_br(offset, ebx.value) + # We might have an exception pending. + mc.load_imm(r.r2, self.cpu.pos_exc_value()) + # Copy it into 'jf_guard_exc' + offset = self.cpu.get_ofs_of_frame_field('jf_guard_exc') + mc.load(r.r0.value, r.r2.value, 0) + mc.store(r.r0.value, r.SPP.value, offset) + # Zero out the exception fields + diff = self.cpu.pos_exception() - self.cpu.pos_exc_value() + assert _check_imm_arg(diff) + mc.li(r.r0.value, 0) + mc.store(r.r0.value, r.r2.value, 0) + mc.store(r.r0.value, r.r2.value, diff) # now we return from the complete frame, which starts from # _call_header_with_stack_check(). The _call_footer below does it. @@ -275,7 +279,7 @@ mc.cmp_op(0, r.RES.value, 0, imm=True) jmp_pos = mc.currpos() - mc.nop() + mc.trap() nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr() mc.load_imm(r.r4, nursery_free_adr) @@ -375,7 +379,7 @@ mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) jnz_location = mc.currpos() - mc.nop() + mc.trap() # restore parameter registers for i, reg in enumerate(r.PARAM_REGS): @@ -600,7 +604,7 @@ self.mc.mfctr(r.r16.value) patch_loc = self.mc.currpos() - self.mc.nop() + self.mc.trap() # make minimal frame which contains the LR # @@ -636,15 +640,16 @@ if gcrootmap and gcrootmap.is_shadow_stack: self._call_footer_shadowstack(gcrootmap) - # load old backchain into r4 - self.mc.load(r.r4.value, r.SP.value, - STD_FRAME_SIZE_IN_BYTES + LR_BC_OFFSET) - # restore registers r25 to r31 for i, reg in enumerate(REGISTERS_SAVED): self.mc.load(reg.value, r.SP.value, GPR_SAVE_AREA_OFFSET + i * WORD) + # load the return address into r4 + self.mc.load(r.r4.value, r.SP.value, + STD_FRAME_SIZE_IN_BYTES + LR_BC_OFFSET) + + # throw away the stack frame and return to r4 self.mc.addi(r.SP.value, r.SP.value, STD_FRAME_SIZE_IN_BYTES) self.mc.mtlr(r.r4.value) # restore LR self.mc.blr() @@ -654,6 +659,7 @@ assert self.memcpy_addr != 0, "setup_once() not called?" self.current_clt = looptoken.compiled_loop_token self.pending_guard_tokens = [] + self.pending_guard_tokens_recovered = 0 #if WORD == 8: # self.pending_memoryerror_trampoline_from = [] # self.error_trampoline_64 = 0 @@ -930,6 +936,21 @@ ptr = rffi.cast(lltype.Signed, gcmap) mc.load_imm(r.r2, ptr) + def break_long_loop(self): + # If the loop is too long, the guards in it will jump forward + # more than 32 KB. We use an approximate hack to know if we + # should break the loop here with an unconditional "b" that + # jumps over the target code. + jmp_pos = self.mc.currpos() + self.mc.trap() + + self.write_pending_failure_recoveries() + + currpos = self.mc.currpos() + pmc = OverwritingBuilder(self.mc, jmp_pos, 1) + pmc.b(currpos - jmp_pos) + pmc.overwrite() + def generate_quick_failure(self, guardtok): startpos = self.mc.currpos() fail_descr, target = self.store_info_on_descr(startpos, guardtok) @@ -944,10 +965,15 @@ def write_pending_failure_recoveries(self): # for each pending guard, generate the code of the recovery stub # at the end of self.mc. - for tok in self.pending_guard_tokens: + for i in range(self.pending_guard_tokens_recovered, + len(self.pending_guard_tokens)): + tok = self.pending_guard_tokens[i] tok.pos_recovery_stub = self.generate_quick_failure(tok) + self.pending_guard_tokens_recovered = len(self.pending_guard_tokens) def patch_pending_failure_recoveries(self, rawstart): + assert (self.pending_guard_tokens_recovered == + len(self.pending_guard_tokens)) clt = self.current_clt for tok in self.pending_guard_tokens: addr = rawstart + tok.pos_jump_offset @@ -988,15 +1014,6 @@ clt.asmmemmgr_blocks = [] return clt.asmmemmgr_blocks - def _prepare_sp_patch_position(self): - """Generate NOPs as placeholder to patch the instruction(s) to update - the sp according to the number of spilled variables""" - size = SIZE_LOAD_IMM_PATCH_SP - l = self.mc.currpos() - for _ in range(size): - self.mc.nop() - return l - def regalloc_mov(self, prev_loc, loc): if prev_loc.is_imm(): value = prev_loc.getint() @@ -1137,29 +1154,6 @@ else: raise AssertionError('Trying to pop to an invalid location') - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 1: - if not signed: #unsigned char - if IS_PPC_32: - self.mc.rlwinm(resloc.value, resloc.value, 0, 24, 31) - else: - self.mc.rldicl(resloc.value, resloc.value, 0, 56) - else: - self.mc.extsb(resloc.value, resloc.value) - elif size == 2: - if not signed: - if IS_PPC_32: - self.mc.rlwinm(resloc.value, resloc.value, 0, 16, 31) - else: - self.mc.rldicl(resloc.value, resloc.value, 0, 48) - else: - self.mc.extsh(resloc.value, resloc.value) - elif size == 4: - if not signed: - self.mc.rldicl(resloc.value, resloc.value, 0, 32) - else: - self.mc.extsw(resloc.value, resloc.value) - def malloc_cond(self, nursery_free_adr, nursery_top_adr, size): assert size & (WORD-1) == 0 # must be correctly aligned @@ -1178,7 +1172,7 @@ self.mc.cmp_op(0, r.r4.value, r.SCRATCH.value, signed=False) fast_jmp_pos = self.mc.currpos() - self.mc.nop() + self.mc.trap() # We load into r3 the address stored at nursery_free_adr. We calculate # the new value for nursery_free_adr and store in r1 The we load the @@ -1212,6 +1206,7 @@ gcrootmap.write_callshape(mark, force_index) def propagate_memoryerror_if_r3_is_null(self): + return # XXXXXXXXX self.mc.cmp_op(0, r.RES.value, 0, imm=True) self.mc.b_cond_abs(self.propagate_exception_path, c.EQ) @@ -1253,6 +1248,10 @@ (op.getopname(), guard_op.getopname()) raise NotImplementedError(op) +def add_none_argument(fn): + return (lambda self, op, arglocs, regalloc: + fn(self, op, None, arglocs, regalloc)) + operations = [notimplemented_op] * (rop._LAST + 1) operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) @@ -1271,8 +1270,10 @@ continue methname = 'emit_guard_%s' % key if hasattr(AssemblerPPC, methname): + assert operations[value] is notimplemented_op func = getattr(AssemblerPPC, methname).im_func operations_with_guard[value] = func + operations[value] = add_none_argument(func) class BridgeAlreadyCompiled(Exception): pass diff --git a/rpython/jit/backend/ppc/regalloc.py b/rpython/jit/backend/ppc/regalloc.py --- a/rpython/jit/backend/ppc/regalloc.py +++ b/rpython/jit/backend/ppc/regalloc.py @@ -6,13 +6,8 @@ from rpython.jit.backend.ppc.jump import (remap_frame_layout, remap_frame_layout_mixed) from rpython.jit.backend.ppc.locations import imm, get_fp_offset -from rpython.jit.backend.ppc.helper.regalloc import (_check_imm_arg, - prepare_cmp_op, - prepare_unary_int_op, - prepare_binary_int_op, - prepare_binary_int_op_with_imm, - prepare_unary_cmp, - prepare_float_op) +from rpython.jit.backend.ppc.helper.regalloc import _check_imm_arg, check_imm_box +from rpython.jit.backend.ppc.helper import regalloc as helper from rpython.jit.metainterp.history import (Const, ConstInt, ConstFloat, ConstPtr, Box, BoxPtr, INT, REF, FLOAT) @@ -32,6 +27,8 @@ from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.rlib import rgc +LIMIT_LOOP_BREAK = 15000 # should be much smaller than 32 KB + # xxx hack: set a default value for TargetToken._arm_loop_code. If 0, we know # that it is a LABEL that was not compiled yet. TargetToken._ppc_loop_code = 0 @@ -56,11 +53,12 @@ class FPRegisterManager(RegisterManager): - all_regs = r.ALL_FLOAT_REGS + all_regs = r.MANAGED_FP_REGS box_types = [FLOAT] save_around_call_regs = r.VOLATILES_FLOAT def convert_to_imm(self, c): + assert isinstance(c, ConstFloat) adr = self.assembler.datablockwrapper.malloc_aligned(8, 8) x = c.getfloatstorage() rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[0] = x @@ -72,25 +70,21 @@ def call_result_location(self, v): return r.f1 - def ensure_value_is_boxed(self, thing, forbidden_vars=[]): - loc = None - if isinstance(thing, Const): - assert isinstance(thing, ConstFloat) - loc = self.get_scratch_reg(FLOAT, self.temp_boxes + forbidden_vars) - immvalue = self.convert_to_imm(thing) + def ensure_reg(self, box): + if isinstance(box, Const): + loc = self.get_scratch_reg() + immvalue = self.convert_to_imm(box) self.assembler.load(loc, immvalue) else: - loc = self.make_sure_var_in_reg(thing, - forbidden_vars=self.temp_boxes + forbidden_vars) + assert box in self.temp_boxes + loc = self.make_sure_var_in_reg(box, + forbidden_vars=self.temp_boxes) return loc - def get_scratch_reg(self, type=FLOAT, forbidden_vars=[], - selected_reg=None): - assert type == FLOAT # for now + def get_scratch_reg(self): box = TempFloat() + reg = self.force_allocate_reg(box, forbidden_vars=self.temp_boxes) self.temp_boxes.append(box) - reg = self.force_allocate_reg(box, forbidden_vars=forbidden_vars, - selected_reg=selected_reg) return reg @@ -142,39 +136,23 @@ assert isinstance(c, ConstPtr) return locations.ImmLocation(rffi.cast(lltype.Signed, c.value)) - def ensure_value_is_boxed(self, thing, forbidden_vars=None): - loc = None - if isinstance(thing, Const): - if isinstance(thing, ConstPtr): - tp = REF - else: - tp = INT - loc = self.get_scratch_reg(tp, forbidden_vars=self.temp_boxes - + forbidden_vars) - immvalue = self.convert_to_imm(thing) + def ensure_reg(self, box): + if isinstance(box, Const): + loc = self.get_scratch_reg() + immvalue = self.convert_to_imm(box) self.assembler.load(loc, immvalue) else: - loc = self.make_sure_var_in_reg(thing, - forbidden_vars=self.temp_boxes + forbidden_vars) + assert box in self.temp_boxes + loc = self.make_sure_var_in_reg(box, + forbidden_vars=self.temp_boxes) return loc - def allocate_scratch_reg(self, type=INT, selected_reg=None, forbidden_vars=None): - """Allocate a scratch register, possibly spilling a managed register. - This register is freed after emitting the current operation and can not - be spilled""" + def get_scratch_reg(self): box = TempBox() From noreply at buildbot.pypy.org Fri Sep 4 09:10:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 09:10:31 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Add three tests that fail on default, about hitting corner cases of Message-ID: <20150904071031.A5EA21C0207@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79406:2ac581d8ddd9 Date: 2015-09-04 09:10 +0200 http://bitbucket.org/pypy/pypy/changeset/2ac581d8ddd9/ Log: Add three tests that fail on default, about hitting corner cases of short preambles when unrolling. diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1009,6 +1009,116 @@ assert f(15) == self.meta_interp(f, [15]) + def test_unroll_issue_1(self): + class A(object): + _attrs_ = [] + def checkcls(self): + raise NotImplementedError + + class B(A): + def __init__(self, b_value): + self.b_value = b_value + def get_value(self): + return self.b_value + def checkcls(self): + return self.b_value + + @dont_look_inside + def check(a): + return isinstance(a, B) + + jitdriver = JitDriver(greens=[], reds='auto') + + def f(a, xx): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point() + if check(a): + if xx & 1: + total *= a.checkcls() + total += a.get_value() + i += 1 + return total + + def run(n): + bt = f(B(n), 1) + bt = f(B(n), 2) + at = f(A(), 3) + return at * 100000 + bt + + assert run(42) == 420 + res = self.meta_interp(run, [42], backendopt=True) + assert res == 420 + + def test_unroll_issue_2(self): + class B(object): + def __init__(self, b_value): + self.b_value = b_value + class C(object): + pass + + from rpython.rlib.rerased import new_erasing_pair + b_erase, b_unerase = new_erasing_pair("B") + c_erase, c_unerase = new_erasing_pair("C") + + @elidable + def unpack_b(a): + return b_unerase(a) + + jitdriver = JitDriver(greens=[], reds='auto') + + def f(a, flag): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point() + if flag: + total += unpack_b(a).b_value + flag += 1 + i += 1 + return total + + def run(n): + res = f(b_erase(B(n)), 1) + f(c_erase(C()), 0) + return res + + assert run(42) == 420 + res = self.meta_interp(run, [42], backendopt=True) + assert res == 420 + + def test_unroll_issue_3(self): + from rpython.rlib.rerased import new_erasing_pair + b_erase, b_unerase = new_erasing_pair("B") # list of ints + c_erase, c_unerase = new_erasing_pair("C") # list of Nones + + @elidable + def unpack_b(a): + return b_unerase(a) + + jitdriver = JitDriver(greens=[], reds='auto') + + def f(a, flag): + i = 0 + total = 0 + while i < 10: + jitdriver.jit_merge_point() + if flag: + total += unpack_b(a)[0] + flag += 1 + i += 1 + return total + + def run(n): + res = f(b_erase([n]), 1) + f(c_erase([None]), 0) + return res + + assert run(42) == 420 + res = self.meta_interp(run, [42], backendopt=True) + assert res == 420 + class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Fri Sep 4 09:12:06 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 09:12:06 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: kill a bogus test - val2 gets promoted Message-ID: <20150904071206.C38AD1C0207@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79407:de24044ac55c Date: 2015-09-04 09:12 +0200 http://bitbucket.org/pypy/pypy/changeset/de24044ac55c/ Log: kill a bogus test - val2 gets promoted diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -953,62 +953,6 @@ res = self.meta_interp(f, [20, 10]) assert res == f(20, 10) - def test_subclasses_dont_match(self): - class A(object): - def __init__(self, val): - self.val = val - - def getval(self): - return self.val - - class B(A): - def __init__(self, foo, val): - self.foo = foo - self.val = val - self.val2 = val - - def getval(self): - return self.val2 - - class Container(object): - def __init__(self, x): - self.x = x - - myjitdriver = JitDriver(greens = [], reds = 'auto') - - @dont_look_inside - def externfn(a, i): - if i > 7: - return 1 - return 0 - - class Foo(Exception): - pass - - @dont_look_inside - def checkclass(a): - if type(a) is not B: - raise Foo() - - def f(n): - i = 0 - a = Container(B(A(n), n)) - b = Container(A(n)) - s = 0 - while i < n: - myjitdriver.jit_merge_point() - i += 1 - try: - checkclass(a.x) - except Foo: - pass - else: - s += a.x.val2 - if externfn(a, i): - a = b - - assert f(15) == self.meta_interp(f, [15]) - def test_unroll_issue_1(self): class A(object): _attrs_ = [] From noreply at buildbot.pypy.org Fri Sep 4 09:40:32 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 09:40:32 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: finish fixing test_virtual. Skip 2 of new tests Message-ID: <20150904074032.B6E171C050C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79408:9d170d9c6c8c Date: 2015-09-04 09:40 +0200 http://bitbucket.org/pypy/pypy/changeset/9d170d9c6c8c/ Log: finish fixing test_virtual. Skip 2 of new tests diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -104,13 +104,15 @@ run of LoopCompileData. Jump goes to the same label """ def __init__(self, start_label, end_jump, operations, state, - call_pure_results=None, enable_opts=None): + call_pure_results=None, enable_opts=None, + inline_short_preamble=True): self.start_label = start_label self.end_jump = end_jump self.operations = operations self.enable_opts = enable_opts self.state = state self.call_pure_results = call_pure_results + self.inline_short_preamble = inline_short_preamble def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll): from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer @@ -118,7 +120,8 @@ assert unroll # we should not be here if it's disabled opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.optimize_peeled_loop(self.start_label, self.end_jump, - self.operations, self.state, self.call_pure_results) + self.operations, self.state, self.call_pure_results, + self.inline_short_preamble) def show_procedures(metainterp_sd, procedure=None, error=None): # debugging @@ -339,40 +342,31 @@ loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: - xxxx # Fall back on jumping directly to preamble - jump_op = ResOperation(rop.JUMP, inputargs[:], - descr=loop_jitcell_token.target_tokens[0]) - loop_data = SimpleCompileData(end_label, - [jump_op], - call_pure_results, - enable_opts) + jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token) + loop_data = UnrolledLoopData(end_label, jump_op, [jump_op], start_state, + call_pure_results=call_pure_results, + enable_opts=enable_opts, + inline_short_preamble=False) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, loop_data) except InvalidLoop: return None - loop = partial_trace - loop.original_jitcell_token = loop_jitcell_token - import pdb - pdb.set_trace() - loop.operations = loop.operations + loop_ops[:] - loop.check_consistency() - else: - loop = partial_trace - loop.original_jitcell_token = loop_jitcell_token - loop.operations = (loop.operations + loop_info.extra_same_as + - [loop_info.label_op] - + loop_ops) + loop = partial_trace + loop.original_jitcell_token = loop_jitcell_token + loop.operations = (loop.operations + loop_info.extra_same_as + + [loop_info.label_op] + + loop_ops) - quasi_immutable_deps = {} - if loop_info.quasi_immutable_deps: - quasi_immutable_deps.update(loop_info.quasi_immutable_deps) - if start_state.quasi_immutable_deps: - quasi_immutable_deps.update(start_state.quasi_immutable_deps) - if quasi_immutable_deps: - loop.quasi_immutable_deps = quasi_immutable_deps + quasi_immutable_deps = {} + if loop_info.quasi_immutable_deps: + quasi_immutable_deps.update(loop_info.quasi_immutable_deps) + if start_state.quasi_immutable_deps: + quasi_immutable_deps.update(start_state.quasi_immutable_deps) + if quasi_immutable_deps: + loop.quasi_immutable_deps = quasi_immutable_deps target_token = loop.operations[-1].getdescr() resumekey.compile_and_attach(metainterp, loop, inputargs) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -122,7 +122,7 @@ return exported_state, self.optimizer._newoperations def optimize_peeled_loop(self, start_label, end_jump, ops, state, - call_pure_results): + call_pure_results, inline_short_preamble=True): self._check_no_forwarding([[start_label, end_jump], ops]) label_args = self.import_state(start_label, state) self.potential_extra_ops = {} @@ -138,6 +138,7 @@ # pick the vs we want to jump to celltoken = start_label.getdescr() assert isinstance(celltoken, JitCellToken) + target_virtual_state = self.pick_virtual_state(current_vs, state.virtual_state, celltoken.target_tokens) @@ -154,6 +155,13 @@ target_token = self.finalize_short_preamble(label_op, state.virtual_state) label_op.setdescr(target_token) + + if not inline_short_preamble: + self.jump_to_preamble(celltoken, end_jump, info) + return (UnrollInfo(target_token, label_op, [], + self.optimizer.quasi_immutable_deps), + self.optimizer._newoperations) + try: new_virtual_state = self.jump_to_existing_trace(end_jump, label_op) except InvalidLoop: diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1,5 +1,6 @@ import py -from rpython.rlib.jit import JitDriver, hint, set_param, dont_look_inside +from rpython.rlib.jit import JitDriver, hint, set_param, dont_look_inside,\ + elidable from rpython.rlib.objectmodel import compute_hash from rpython.jit.metainterp.warmspot import ll_meta_interp, get_stats from rpython.jit.metainterp.test.support import LLJitMixin @@ -15,11 +16,12 @@ 'guard_value' : 3 } - def meta_interp(self, f, args, policy=None): + def meta_interp(self, f, args, policy=None, backendopt=False): return ll_meta_interp(f, args, enable_opts=self.enable_opts, policy=policy, CPUClass=self.CPUClass, - type_system=self.type_system) + type_system=self.type_system, + backendopt=backendopt) def run_directly(self, f, args): return f(*args) @@ -996,6 +998,8 @@ assert res == 420 def test_unroll_issue_2(self): + py.test.skip("decide") + class B(object): def __init__(self, b_value): self.b_value = b_value @@ -1033,6 +1037,8 @@ assert res == 420 def test_unroll_issue_3(self): + py.test.skip("decide") + from rpython.rlib.rerased import new_erasing_pair b_erase, b_unerase = new_erasing_pair("B") # list of ints c_erase, c_unerase = new_erasing_pair("C") # list of Nones From noreply at buildbot.pypy.org Fri Sep 4 09:59:31 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 09:59:31 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: implement proper subclass check Message-ID: <20150904075931.244F41C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79409:b16ba648cd4f Date: 2015-09-04 09:59 +0200 http://bitbucket.org/pypy/pypy/changeset/b16ba648cd4f/ Log: implement proper subclass check diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -12,6 +12,8 @@ from rpython.jit.metainterp.resoperation import rop, ResOperation, opclasses,\ OpHelpers from rpython.rlib.rarithmetic import highest_bit +from rpython.rtyper.lltypesystem import llmemory +from rpython.rtyper import rclass import math class OptRewrite(Optimization): @@ -309,17 +311,31 @@ return self.emit_operation(op) + def _check_subclass(self, vtable1, vtable2): + # checks that vtable1 is a subclass of vtable2 + known_class = llmemory.cast_adr_to_ptr( + llmemory.cast_int_to_adr(vtable1), + rclass.CLASSTYPE) + expected_class = llmemory.cast_adr_to_ptr( + llmemory.cast_int_to_adr(vtable2), + rclass.CLASSTYPE) + if (expected_class.subclassrange_min + <= known_class.subclassrange_min + <= expected_class.subclassrange_max): + return True + return False + def optimize_GUARD_SUBCLASS(self, op): info = self.getptrinfo(op.getarg(0)) if info is not None and info.is_about_object(): known_class = info.get_known_class(self.optimizer.cpu) if known_class: - if known_class.getint() == op.getarg(1).getint(): - # XXX subclass check + if self._check_subclass(known_class.getint(), + op.getarg(1).getint()): return elif info.get_descr() is not None: - if info.get_descr().get_vtable() == op.getarg(1).getint(): - # XXX check for actual subclass? + if self._check_subclass(info.get_descr().get_vtable(), + op.getarg(1).getint()): return self.emit_operation(op) From noreply at buildbot.pypy.org Fri Sep 4 10:28:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 10:28:10 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Untested so far: guard_is_object Message-ID: <20150904082810.6AD631C1414@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79410:39efc5926eb8 Date: 2015-09-04 10:28 +0200 http://bitbucket.org/pypy/pypy/changeset/39efc5926eb8/ Log: Untested so far: guard_is_object diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -438,6 +438,7 @@ self._make_gcrootmap() self._setup_gcclass() self._setup_tid() + self._setup_guard_is_object() self._setup_write_barrier() self._setup_str() self._make_functions(really_not_translated) @@ -662,6 +663,48 @@ def get_malloc_slowpath_array_addr(self): return self.get_malloc_fn_addr('malloc_array') + def get_typeid_from_classptr_if_gcremovetypeptr(self, classptr): + """Returns the typeid corresponding from a vtable pointer 'classptr'. + This function only works if cpu.vtable_offset is None, i.e. in + a translation with --gcremovetypeptr. + """ + from rpython.memory.gctypelayout import GCData + assert translator.config.translation.gcremovetypeptr + + # hard-coded assumption: to go from an object to its class + # we would use the following algorithm: + # - read the typeid from mem(locs[0]), i.e. at offset 0; + # this is a complete word (N=4 bytes on 32-bit, N=8 on + # 64-bits) + # - keep the lower half of what is read there (i.e. + # truncate to an unsigned 'N / 2' bytes value) + # - multiply by 4 (on 32-bits only) and use it as an + # offset in type_info_group + # - add 16/32 bytes, to go past the TYPE_INFO structure + # here, we have to go back from 'classptr' back to the typeid, + # so we do (part of) these computations in reverse. + + sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + expected_typeid = classptr - sizeof_ti - type_info_group + if IS_X86_32: + expected_typeid >>= 2 + return expected_typeid + + def _setup_guard_is_object(self): + from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE + self._infobits_offset = symbolic.get_field_token(GCData.TYPE_INFO, + 'infobits', True) + self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE + + def get_translated_info_for_guard_is_object(self): + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) + return (type_info_group + infobits_offset, self._T_IS_RPYTHON_INSTANCE) + + # ____________________________________________________________ def get_ll_description(gcdescr, translator=None, rtyper=None): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1741,25 +1741,10 @@ if offset is not None: self.mc.CMP(mem(loc_ptr, offset), loc_classptr) else: - # XXX hard-coded assumption: to go from an object to its class - # we use the following algorithm: - # - read the typeid from mem(locs[0]), i.e. at offset 0; - # this is a complete word (N=4 bytes on 32-bit, N=8 on - # 64-bits) - # - keep the lower half of what is read there (i.e. - # truncate to an unsigned 'N / 2' bytes value) - # - multiply by 4 (on 32-bits only) and use it as an - # offset in type_info_group - # - add 16/32 bytes, to go past the TYPE_INFO structure assert isinstance(loc_classptr, ImmedLoc) classptr = loc_classptr.value - # here, we have to go back from 'classptr' to the value expected - # from reading the half-word in the object header. - from rpython.memory.gctypelayout import GCData - sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) - expected_typeid = classptr - sizeof_ti - type_info_group + expected_typeid = (self.cpu.gc_ll_descr + .get_typeid_from_classptr_if_gcremovetypeptr(classptr)) self._cmp_guard_gc_type(loc_ptr, ImmedLoc(expected_typeid)) def _cmp_guard_gc_type(self, loc_ptr, loc_expected_typeid): @@ -1795,6 +1780,25 @@ self._cmp_guard_gc_type(locs[0], locs[1]) self.implement_guard(guard_token, 'NE') + def genop_guard_guard_is_object(self, ign_1, guard_op, + guard_token, locs, ign_2): + assert self.cpu.supports_guard_gc_type + [loc_object, loc_typeid] = locs + # idea: read the typeid, fetch the field 'infobits' from the big + # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + base_type_info, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + if IS_X86_32: + self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) + shift_by = 2 + else: + self.mc.MOVZX32(loc_typeid, mem(loc_object, 0)) + shift_by = 0 + loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) + self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) + # + self.implement_guard(guard_token, 'Z') + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): exc = (guard_opnum == rop.GUARD_EXCEPTION or diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -431,7 +431,11 @@ consider_guard_gc_type = consider_guard_class def consider_guard_is_object(self, op): - xxx + x = self.make_sure_var_in_reg(op.getarg(0)) + tmp_box = TempVar() + y = self.rm.force_allocate_reg(tmp_box) + self.rm.possibly_free_var(tmp_box) + self.perform_guard(op, [x, y], None) def consider_guard_subclass(self, op): xxx From noreply at buildbot.pypy.org Fri Sep 4 10:40:12 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 10:40:12 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: probable fix, but really needs tests Message-ID: <20150904084012.825D81C12D6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79411:6c3f58de10b2 Date: 2015-09-04 10:40 +0200 http://bitbucket.org/pypy/pypy/changeset/6c3f58de10b2/ Log: probable fix, but really needs tests diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -688,7 +688,7 @@ type_info_group = llop.gc_get_type_info_group(llmemory.Address) type_info_group = rffi.cast(lltype.Signed, type_info_group) expected_typeid = classptr - sizeof_ti - type_info_group - if IS_X86_32: + if WORD == 4: expected_typeid >>= 2 return expected_typeid @@ -702,7 +702,13 @@ type_info_group = llop.gc_get_type_info_group(llmemory.Address) type_info_group = rffi.cast(lltype.Signed, type_info_group) infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) - return (type_info_group + infobits_offset, self._T_IS_RPYTHON_INSTANCE) + if WORD == 4: + shift_by = 2 + elif WORD == 8: + shift_by = 0 + return (type_info_group + infobits_offset, + shift_by, + self._T_IS_RPYTHON_INSTANCE) # ____________________________________________________________ diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1786,14 +1786,12 @@ [loc_object, loc_typeid] = locs # idea: read the typeid, fetch the field 'infobits' from the big # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. - base_type_info, IS_OBJECT_FLAG = ( + base_type_info, shift_by, IS_OBJECT_FLAG = ( self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) if IS_X86_32: self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) - shift_by = 2 else: self.mc.MOVZX32(loc_typeid, mem(loc_object, 0)) - shift_by = 0 loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) # From noreply at buildbot.pypy.org Fri Sep 4 10:49:42 2015 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 4 Sep 2015 10:49:42 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: progress is progess. Fixes issue #2055 Message-ID: <20150904084942.8C8BC1C12F1@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: extradoc Changeset: r632:7da6a7219a92 Date: 2015-09-04 11:50 +0300 http://bitbucket.org/pypy/pypy.org/changeset/7da6a7219a92/ Log: progress is progess. Fixes issue #2055 diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -69,7 +69,7 @@

Python compatibility

-

PyPy implements the Python language version 2.7.9. It supports all of the core +

PyPy implements the Python language version 2.7.10. It supports all of the core language, passing Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python standard library modules; details below.

diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -72,7 +72,7 @@

PyPy is a replacement for CPython. It is built using the RPython language that was co-developed with it. The main reason to use it instead of CPython is speed: it runs generally faster (see next section).

-

PyPy 2.5 implements Python 2.7.9 and runs on Intel +

PyPy 2.5 implements Python 2.7.10 and runs on Intel x86 (IA-32) , x86_64 and ARM platforms, with PPC being stalled. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -70,7 +70,7 @@

Welcome to PyPy

PyPy is a fast, compliant alternative implementation of the Python -language (2.7.9 and 3.2.5). It has several advantages and distinct features:

+language (2.7.10 and 3.2.5). It has several advantages and distinct features:

  • Speed: thanks to its Just-in-Time compiler, Python programs diff --git a/source/compat.txt b/source/compat.txt --- a/source/compat.txt +++ b/source/compat.txt @@ -3,7 +3,7 @@ title: Python compatibility --- -PyPy implements the Python language version 2.7.9. It supports all of the core +PyPy implements the Python language version 2.7.10. It supports all of the core language, passing Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python `standard library modules`_; details below. diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -10,7 +10,7 @@ language that was co-developed with it. The main reason to use it instead of CPython is speed: it runs generally faster (see next section). -**PyPy 2.5** implements **Python 2.7.9** and runs on Intel +**PyPy 2.5** implements **Python 2.7.10** and runs on Intel `x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms, with PPC being stalled. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/source/index.txt b/source/index.txt --- a/source/index.txt +++ b/source/index.txt @@ -4,7 +4,7 @@ --- PyPy is a `fast`_, `compliant`_ alternative implementation of the `Python`_ -language (2.7.9 and 3.2.5). It has several advantages and distinct features: +language (2.7.10 and 3.2.5). It has several advantages and distinct features: * **Speed:** thanks to its Just-in-Time compiler, Python programs often run `faster`_ on PyPy. `(What is a JIT compiler?)`_ From noreply at buildbot.pypy.org Fri Sep 4 11:55:21 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 11:55:21 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: (fijal, arigo) Trying to write a direct, translated test for Message-ID: <20150904095521.6FF891C1F97@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79412:3a328bfeb255 Date: 2015-09-04 11:55 +0200 http://bitbucket.org/pypy/pypy/changeset/3a328bfeb255/ Log: (fijal, arigo) Trying to write a direct, translated test for the code that can only be tested when translated, here in guard_class diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -24,6 +24,7 @@ class MovableObjectTracker(object): ptr_array_type = lltype.GcArray(llmemory.GCREF) + ptr_array_gcref = lltype.nullptr(llmemory.GCREF.TO) def __init__(self, cpu, const_pointers): size = len(const_pointers) @@ -669,7 +670,7 @@ a translation with --gcremovetypeptr. """ from rpython.memory.gctypelayout import GCData - assert translator.config.translation.gcremovetypeptr + assert self.gcdescr.config.translation.gcremovetypeptr # hard-coded assumption: to go from an object to its class # we would use the following algorithm: diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -25,6 +25,12 @@ HAS_CODEMAP = False + done_with_this_frame_descr_int = None # overridden by pyjitpl.py + done_with_this_frame_descr_float = None + done_with_this_frame_descr_ref = None + done_with_this_frame_descr_void = None + exit_frame_with_exception_descr_ref = None + def __init__(self, rtyper, stats, opts, translate_support_code=False, gcdescr=None): assert type(opts) is not bool diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -0,0 +1,60 @@ +from rpython.jit.backend.detect_cpu import getcpuclass +from rpython.jit.tool.oparser import parse +from rpython.jit.metainterp.history import JitCellToken, NoStats +from rpython.jit.metainterp.history import BasicFinalDescr, BasicFailDescr +from rpython.jit.metainterp.gc import get_description +from rpython.annotator.listdef import s_list_of_strings +from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper.rclass import getclassrepr +from rpython.translator.unsimplify import call_initial_function +from rpython.translator.translator import TranslationContext + + +def test_guard_class(): + class A(object): + pass + class B(A): + pass + class C(B): + pass + def main(argv): + A(); B(); C() + return 0 + + t = TranslationContext() + t.config.translation.gc = "minimark" + t.config.translation.gcremovetypeptr = True + ann = t.buildannotator() + ann.build_types(main, [s_list_of_strings], main_entry_point=True) + rtyper = t.buildrtyper() + rtyper.specialize() + + classdef = ann.bookkeeper.getuniqueclassdef(B) + rclass = getclassrepr(rtyper, classdef) + vtable_B = rclass.getvtable() + adr_vtable_B = llmemory.cast_ptr_to_adr(vtable_B) + vtable_B = llmemory.cast_adr_to_int(adr_vtable_B, mode="symbolic") + + CPU = getcpuclass() + cpu = CPU(rtyper, NoStats(), + translate_support_code=True, + gcdescr=get_description(t.config)) + + loop = parse(""" + [p0] + guard_class(p0, ConstInt(vtable_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': BasicFinalDescr(), + 'faildescr': BasicFailDescr(), + 'vtable_B': vtable_B}) + + def g(): + cpu.setup_once() + token = JitCellToken() + cpu.compile_loop(loop.inputargs, loop.operations, token) + + # xxx + + call_initial_function(t, g) + +#...turn to C here diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1791,7 +1791,7 @@ if IS_X86_32: self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) else: - self.mc.MOVZX32(loc_typeid, mem(loc_object, 0)) + self.mc.MOV32(loc_typeid, mem(loc_object, 0)) loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) # diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -438,7 +438,7 @@ self.perform_guard(op, [x, y], None) def consider_guard_subclass(self, op): - xxx + assert 0 # xxx def _consider_binop_part(self, op, symm=False): x = op.getarg(0) @@ -802,6 +802,7 @@ def _consider_real_call(self, op): effectinfo = op.getdescr().get_extra_info() + assert effectinfo is not None oopspecindex = effectinfo.oopspecindex if oopspecindex != EffectInfo.OS_NONE: if IS_X86_32: From noreply at buildbot.pypy.org Fri Sep 4 13:20:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 13:20:36 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Finish the test; it passes on x86 Message-ID: <20150904112036.746861C12F1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79413:c04ede48ab19 Date: 2015-09-04 12:30 +0200 http://bitbucket.org/pypy/pypy/changeset/c04ede48ab19/ Log: Finish the test; it passes on x86 diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py --- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -4,10 +4,11 @@ from rpython.jit.metainterp.history import BasicFinalDescr, BasicFailDescr from rpython.jit.metainterp.gc import get_description from rpython.annotator.listdef import s_list_of_strings -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.rclass import getclassrepr from rpython.translator.unsimplify import call_initial_function from rpython.translator.translator import TranslationContext +from rpython.translator.c import genc def test_guard_class(): @@ -39,13 +40,16 @@ cpu = CPU(rtyper, NoStats(), translate_support_code=True, gcdescr=get_description(t.config)) + execute_token = cpu.make_execute_token(llmemory.GCREF) + finaldescr = BasicFinalDescr() + faildescr = BasicFailDescr() loop = parse(""" [p0] guard_class(p0, ConstInt(vtable_B), descr=faildescr) [] finish(descr=finaldescr) - """, namespace={'finaldescr': BasicFinalDescr(), - 'faildescr': BasicFailDescr(), + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, 'vtable_B': vtable_B}) def g(): @@ -53,8 +57,22 @@ token = JitCellToken() cpu.compile_loop(loop.inputargs, loop.operations, token) - # xxx + for x in [A(),B(), C()]: + p0 = rffi.cast(llmemory.GCREF, x) + frame = execute_token(token, p0) + descr = cpu.get_latest_descr(frame) + if descr is finaldescr: + print 'match' + elif descr is faildescr: + print 'fail' + else: + print '???' call_initial_function(t, g) -#...turn to C here + cbuilder = genc.CStandaloneBuilder(t, main, t.config) + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) + cbuilder.compile() + + data = cbuilder.cmdexec('') + assert data == 'fail\nmatch\nfail\n' From noreply at buildbot.pypy.org Fri Sep 4 13:20:38 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 13:20:38 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Also test some other guards, and run with or without gcremovetypeptr Message-ID: <20150904112038.84DA91C12F1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79414:18b4835f4afb Date: 2015-09-04 12:50 +0200 http://bitbucket.org/pypy/pypy/changeset/18b4835f4afb/ Log: Also test some other guards, and run with or without gcremovetypeptr 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 @@ -64,7 +64,7 @@ return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self.vtable)) def get_type_id(self): - assert self.tid != 0 + assert self.tid return self.tid def get_size_descr(gccache, STRUCT, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): @@ -293,7 +293,7 @@ assert False def get_type_id(self): - assert self.tid != 0 + assert self.tid return self.tid def repr_of_descr(self): diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py --- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -5,13 +5,13 @@ from rpython.jit.metainterp.gc import get_description from rpython.annotator.listdef import s_list_of_strings from rpython.rtyper.lltypesystem import lltype, llmemory, rffi -from rpython.rtyper.rclass import getclassrepr +from rpython.rtyper.rclass import getclassrepr, getinstancerepr from rpython.translator.unsimplify import call_initial_function from rpython.translator.translator import TranslationContext from rpython.translator.c import genc -def test_guard_class(): +def run_guards_translated(gcremovetypeptr): class A(object): pass class B(A): @@ -24,7 +24,7 @@ t = TranslationContext() t.config.translation.gc = "minimark" - t.config.translation.gcremovetypeptr = True + t.config.translation.gcremovetypeptr = gcremovetypeptr ann = t.buildannotator() ann.build_types(main, [s_list_of_strings], main_entry_point=True) rtyper = t.buildrtyper() @@ -32,6 +32,8 @@ classdef = ann.bookkeeper.getuniqueclassdef(B) rclass = getclassrepr(rtyper, classdef) + rinstance = getinstancerepr(rtyper, classdef) + LLB = rinstance.lowleveltype.TO vtable_B = rclass.getvtable() adr_vtable_B = llmemory.cast_ptr_to_adr(vtable_B) vtable_B = llmemory.cast_adr_to_int(adr_vtable_B, mode="symbolic") @@ -44,7 +46,10 @@ finaldescr = BasicFinalDescr() faildescr = BasicFailDescr() - loop = parse(""" + descr_B = cpu.sizeof(LLB, vtable_B) + typeid_B = descr_B.get_type_id() + + loop1 = parse(""" [p0] guard_class(p0, ConstInt(vtable_B), descr=faildescr) [] finish(descr=finaldescr) @@ -52,13 +57,44 @@ 'faildescr': faildescr, 'vtable_B': vtable_B}) + loop2 = parse(""" + [p0] + guard_gc_type(p0, ConstInt(typeid_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, + 'typeid_B': typeid_B}) + + loop3 = parse(""" + [p0] + guard_is_object(p0, descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr}) + def g(): cpu.setup_once() - token = JitCellToken() - cpu.compile_loop(loop.inputargs, loop.operations, token) + token1 = JitCellToken() + token2 = JitCellToken() + token3 = JitCellToken() + cpu.compile_loop(loop1.inputargs, loop1.operations, token1) + cpu.compile_loop(loop2.inputargs, loop2.operations, token2) + cpu.compile_loop(loop3.inputargs, loop3.operations, token3) - for x in [A(),B(), C()]: - p0 = rffi.cast(llmemory.GCREF, x) + for token, p0 in [ + (token1, rffi.cast(llmemory.GCREF, A())), + (token1, rffi.cast(llmemory.GCREF, B())), + (token1, rffi.cast(llmemory.GCREF, C())), + + (token2, rffi.cast(llmemory.GCREF, A())), + (token2, rffi.cast(llmemory.GCREF, B())), + (token2, rffi.cast(llmemory.GCREF, C())), + (token2, rffi.cast(llmemory.GCREF, [42, 43])), + + (token3, rffi.cast(llmemory.GCREF, A())), + (token3, rffi.cast(llmemory.GCREF, B())), + (token3, rffi.cast(llmemory.GCREF, [44, 45])), + ]: frame = execute_token(token, p0) descr = cpu.get_latest_descr(frame) if descr is finaldescr: @@ -75,4 +111,22 @@ cbuilder.compile() data = cbuilder.cmdexec('') - assert data == 'fail\nmatch\nfail\n' + assert data == ('fail\n' + 'match\n' + 'fail\n' + + 'fail\n' + 'match\n' + 'fail\n' + 'fail\n' + + 'match\n' + 'match\n' + 'fail\n') + + +def test_guards_translated_with_gctypeptr(): + run_guards_translated(gcremovetypeptr=False) + +def test_guards_translated_without_gctypeptr(): + run_guards_translated(gcremovetypeptr=True) From noreply at buildbot.pypy.org Fri Sep 4 13:20:40 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 13:20:40 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Fixes, the full test passes now. Message-ID: <20150904112040.91E691C12F1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79415:9a490fdd4129 Date: 2015-09-04 13:20 +0200 http://bitbucket.org/pypy/pypy/changeset/9a490fdd4129/ Log: Fixes, the full test passes now. diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -695,8 +695,8 @@ def _setup_guard_is_object(self): from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE - self._infobits_offset = symbolic.get_field_token(GCData.TYPE_INFO, - 'infobits', True) + self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, + 'infobits', True) self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE def get_translated_info_for_guard_is_object(self): diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -674,6 +674,9 @@ TEST8_bi = insn(rex_nw, '\xF6', orbyte(0<<3), stack_bp(1), immediate(2, 'b')) TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + TEST_ai = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_scaled_reg_plus_const(1), immediate(2)) + TEST_mi = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_const(1), immediate(2)) + TEST_ji = insn(rex_w, '\xF7', orbyte(0<<3), abs_(1), immediate(2)) BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_(1)) From noreply at buildbot.pypy.org Fri Sep 4 13:28:35 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 13:28:35 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: only emit guard_is_object if we need it Message-ID: <20150904112835.62B8B1C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79416:bd8b6b4b646a Date: 2015-09-04 13:22 +0200 http://bitbucket.org/pypy/pypy/changeset/bd8b6b4b646a/ Log: only emit guard_is_object if we need it diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -37,6 +37,7 @@ self.translate_support_code = translate_support_code if translate_support_code and rtyper is not None: translator = rtyper.annotator.translator + self.remove_gctypeptr = translator.config.translation.gcremovetypeptr else: translator = None self.gc_ll_descr = get_ll_description(gcdescr, translator, rtyper) diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py --- a/rpython/jit/backend/model.py +++ b/rpython/jit/backend/model.py @@ -19,6 +19,8 @@ propagate_exception_descr = None + remove_gctypeptr = False + def __init__(self): self.tracker = CPUTotalTracker() 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 @@ -75,7 +75,7 @@ def copy_fields_to_const(self, constinfo, optheap): pass - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): pass class NonNullPtrInfo(PtrInfo): @@ -108,7 +108,7 @@ return return self._visitor_walk_recursive(instbox, visitor, optimizer) - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): op = ResOperation(rop.GUARD_NONNULL, [op], None) short.append(op) @@ -307,29 +307,28 @@ assert self.is_virtual() return visitor.visit_virtual(self.descr, fielddescrs) - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): if self._known_class is not None: - short.extend([ - ResOperation(rop.GUARD_NONNULL, [op], None), - ResOperation(rop.GUARD_IS_OBJECT, [op], None), - ResOperation(rop.GUARD_CLASS, [op, self._known_class], None) - ]) + short.append(ResOperation(rop.GUARD_NONNULL, [op], None)) + if not optimizer.cpu.remove_gctypeptr: + short.append(ResOperation(rop.GUARD_IS_OBJECT, [op], None)) + short.append(ResOperation(rop.GUARD_CLASS, + [op, self._known_class], None)) elif self.descr is not None: - short.extend([ - ResOperation(rop.GUARD_NONNULL, [op], None), - ResOperation(rop.GUARD_IS_OBJECT, [op], None), - ResOperation(rop.GUARD_SUBCLASS, [op, - ConstInt(self.descr.get_vtable())], None) - ]) + short.append(ResOperation(rop.GUARD_NONNULL, [op], None)) + if not optimizer.cpu.remove_gctypeptr: + short.append(ResOperation(rop.GUARD_IS_OBJECT, [op], None)) + short.append(ResOperation(rop.GUARD_SUBCLASS, [op, + ConstInt(self.descr.get_vtable())], None)) else: - AbstractStructPtrInfo.make_guards(self, op, short) + AbstractStructPtrInfo.make_guards(self, op, short, optimizer) class StructPtrInfo(AbstractStructPtrInfo): def __init__(self, descr, is_virtual=False): self.descr = descr self._is_virtual = is_virtual - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): if self.descr is not None: c_typeid = ConstInt(self.descr.get_type_id()) short.extend([ @@ -565,14 +564,14 @@ self._items[i] = fldbox return op - def make_guards(self, op, short): - AbstractVirtualPtrInfo.make_guards(self, op, short) + def make_guards(self, op, short, optimizer): + AbstractVirtualPtrInfo.make_guards(self, op, short, optimizer) c_type_id = ConstInt(self.descr.get_type_id()) short.append(ResOperation(rop.GUARD_GC_TYPE, [op, c_type_id], None)) if self.lenbound is not None: lenop = ResOperation(rop.ARRAYLEN_GC, [op], descr=self.descr) short.append(lenop) - self.lenbound.make_guards(lenop, short) + self.lenbound.make_guards(lenop, short, optimizer) class ArrayStructInfo(ArrayPtrInfo): def __init__(self, descr, size, is_virtual=False): @@ -648,7 +647,7 @@ def getconst(self): return self._const - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): short.append(ResOperation(rop.GUARD_VALUE, [op, self._const])) def _get_info(self, descr, optheap): @@ -758,5 +757,5 @@ def __init__(self, const): self._const = const - def make_guards(self, op, short): + def make_guards(self, op, short, optimizer): short.append(ResOperation(rop.GUARD_VALUE, [op, self._const])) diff --git a/rpython/jit/metainterp/optimizeopt/intutils.py b/rpython/jit/metainterp/optimizeopt/intutils.py --- a/rpython/jit/metainterp/optimizeopt/intutils.py +++ b/rpython/jit/metainterp/optimizeopt/intutils.py @@ -257,7 +257,7 @@ res.has_upper = self.has_upper return res - def make_guards(self, box, guards): + def make_guards(self, box, guards, optimizer): if self.is_constant(): guards.append(ResOperation(rop.GUARD_VALUE, [box, ConstInt(self.upper)])) diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -355,14 +355,14 @@ if isinstance(arg, AbstractInputArg): info = arg.get_forwarded() if info is not None and info is not empty_info: - info.make_guards(arg, self.short) + info.make_guards(arg, self.short, optimizer) elif arg.get_forwarded() is None: pass else: self.short.append(arg) info = arg.get_forwarded() if info is not empty_info: - info.make_guards(arg, self.short) + info.make_guards(arg, self.short, optimizer) arg.set_forwarded(None) self.short.append(preamble_op) if preamble_op.is_ovf(): @@ -372,7 +372,7 @@ if optimizer is not None: optimizer.setinfo_from_preamble(box, info, None) if info is not empty_info: - info.make_guards(preamble_op, self.short) + info.make_guards(preamble_op, self.short, optimizer) return preamble_op class ShortPreambleBuilder(AbstractShortPreambleBuilder): diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -404,7 +404,8 @@ # confusingly enough, this is done also for pointers # which have the full range as the "bound", so it always works return self._generate_guards_intbounds(other, box, runtime_box, - extra_guards) + extra_guards, + state.optimizer) # the following conditions often peek into the runtime value that the # box had when tracing. This value is only used as an educated guess. @@ -473,7 +474,8 @@ raise VirtualStatesCantMatch("other not constant") assert 0, "unreachable" - def _generate_guards_intbounds(self, other, box, runtime_box, extra_guards): + def _generate_guards_intbounds(self, other, box, runtime_box, extra_guards, + optimizer): if self.intbound is None: return if self.intbound.contains_bound(other.intbound): @@ -482,7 +484,7 @@ self.intbound.contains(runtime_box.getint())): # this may generate a few more guards than needed, but they are # optimized away when emitting them - self.intbound.make_guards(box, extra_guards) + self.intbound.make_guards(box, extra_guards, optimizer) return raise VirtualStatesCantMatch("intbounds don't match") diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -122,8 +122,8 @@ string_optimizer.emit_operation(lengthop) return lengthop - def make_guards(self, op, short): - info.AbstractVirtualPtrInfo.make_guards(self, op, short) + def make_guards(self, op, short, optimizer): + info.AbstractVirtualPtrInfo.make_guards(self, op, short, optimizer) if self.lenbound and self.lenbound.lower >= 1: if self.mode is mode_string: lenop = ResOperation(rop.STRLEN, [op]) @@ -131,7 +131,7 @@ assert self.mode is mode_unicode lenop = ResOperation(rop.UNICODELEN, [op]) short.append(lenop) - self.lenbound.make_guards(lenop, short) + self.lenbound.make_guards(lenop, short, optimizer) def string_copy_parts(self, op, string_optimizer, targetbox, offsetbox, mode): From noreply at buildbot.pypy.org Fri Sep 4 13:28:37 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 13:28:37 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150904112837.84E7D1C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79417:798a1f163fda Date: 2015-09-04 13:28 +0200 http://bitbucket.org/pypy/pypy/changeset/798a1f163fda/ Log: merge 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 @@ -64,7 +64,7 @@ return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self.vtable)) def get_type_id(self): - assert self.tid != 0 + assert self.tid return self.tid def get_size_descr(gccache, STRUCT, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): @@ -293,7 +293,7 @@ assert False def get_type_id(self): - assert self.tid != 0 + assert self.tid return self.tid def repr_of_descr(self): diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -24,6 +24,7 @@ class MovableObjectTracker(object): ptr_array_type = lltype.GcArray(llmemory.GCREF) + ptr_array_gcref = lltype.nullptr(llmemory.GCREF.TO) def __init__(self, cpu, const_pointers): size = len(const_pointers) @@ -438,6 +439,7 @@ self._make_gcrootmap() self._setup_gcclass() self._setup_tid() + self._setup_guard_is_object() self._setup_write_barrier() self._setup_str() self._make_functions(really_not_translated) @@ -662,6 +664,54 @@ def get_malloc_slowpath_array_addr(self): return self.get_malloc_fn_addr('malloc_array') + def get_typeid_from_classptr_if_gcremovetypeptr(self, classptr): + """Returns the typeid corresponding from a vtable pointer 'classptr'. + This function only works if cpu.vtable_offset is None, i.e. in + a translation with --gcremovetypeptr. + """ + from rpython.memory.gctypelayout import GCData + assert self.gcdescr.config.translation.gcremovetypeptr + + # hard-coded assumption: to go from an object to its class + # we would use the following algorithm: + # - read the typeid from mem(locs[0]), i.e. at offset 0; + # this is a complete word (N=4 bytes on 32-bit, N=8 on + # 64-bits) + # - keep the lower half of what is read there (i.e. + # truncate to an unsigned 'N / 2' bytes value) + # - multiply by 4 (on 32-bits only) and use it as an + # offset in type_info_group + # - add 16/32 bytes, to go past the TYPE_INFO structure + # here, we have to go back from 'classptr' back to the typeid, + # so we do (part of) these computations in reverse. + + sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + expected_typeid = classptr - sizeof_ti - type_info_group + if WORD == 4: + expected_typeid >>= 2 + return expected_typeid + + def _setup_guard_is_object(self): + from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE + self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, + 'infobits', True) + self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE + + def get_translated_info_for_guard_is_object(self): + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) + if WORD == 4: + shift_by = 2 + elif WORD == 8: + shift_by = 0 + return (type_info_group + infobits_offset, + shift_by, + self._T_IS_RPYTHON_INSTANCE) + + # ____________________________________________________________ def get_ll_description(gcdescr, translator=None, rtyper=None): diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -25,6 +25,12 @@ HAS_CODEMAP = False + done_with_this_frame_descr_int = None # overridden by pyjitpl.py + done_with_this_frame_descr_float = None + done_with_this_frame_descr_ref = None + done_with_this_frame_descr_void = None + exit_frame_with_exception_descr_ref = None + def __init__(self, rtyper, stats, opts, translate_support_code=False, gcdescr=None): assert type(opts) is not bool diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -0,0 +1,132 @@ +from rpython.jit.backend.detect_cpu import getcpuclass +from rpython.jit.tool.oparser import parse +from rpython.jit.metainterp.history import JitCellToken, NoStats +from rpython.jit.metainterp.history import BasicFinalDescr, BasicFailDescr +from rpython.jit.metainterp.gc import get_description +from rpython.annotator.listdef import s_list_of_strings +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper.rclass import getclassrepr, getinstancerepr +from rpython.translator.unsimplify import call_initial_function +from rpython.translator.translator import TranslationContext +from rpython.translator.c import genc + + +def run_guards_translated(gcremovetypeptr): + class A(object): + pass + class B(A): + pass + class C(B): + pass + def main(argv): + A(); B(); C() + return 0 + + t = TranslationContext() + t.config.translation.gc = "minimark" + t.config.translation.gcremovetypeptr = gcremovetypeptr + ann = t.buildannotator() + ann.build_types(main, [s_list_of_strings], main_entry_point=True) + rtyper = t.buildrtyper() + rtyper.specialize() + + classdef = ann.bookkeeper.getuniqueclassdef(B) + rclass = getclassrepr(rtyper, classdef) + rinstance = getinstancerepr(rtyper, classdef) + LLB = rinstance.lowleveltype.TO + vtable_B = rclass.getvtable() + adr_vtable_B = llmemory.cast_ptr_to_adr(vtable_B) + vtable_B = llmemory.cast_adr_to_int(adr_vtable_B, mode="symbolic") + + CPU = getcpuclass() + cpu = CPU(rtyper, NoStats(), + translate_support_code=True, + gcdescr=get_description(t.config)) + execute_token = cpu.make_execute_token(llmemory.GCREF) + finaldescr = BasicFinalDescr() + faildescr = BasicFailDescr() + + descr_B = cpu.sizeof(LLB, vtable_B) + typeid_B = descr_B.get_type_id() + + loop1 = parse(""" + [p0] + guard_class(p0, ConstInt(vtable_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, + 'vtable_B': vtable_B}) + + loop2 = parse(""" + [p0] + guard_gc_type(p0, ConstInt(typeid_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, + 'typeid_B': typeid_B}) + + loop3 = parse(""" + [p0] + guard_is_object(p0, descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr}) + + def g(): + cpu.setup_once() + token1 = JitCellToken() + token2 = JitCellToken() + token3 = JitCellToken() + cpu.compile_loop(loop1.inputargs, loop1.operations, token1) + cpu.compile_loop(loop2.inputargs, loop2.operations, token2) + cpu.compile_loop(loop3.inputargs, loop3.operations, token3) + + for token, p0 in [ + (token1, rffi.cast(llmemory.GCREF, A())), + (token1, rffi.cast(llmemory.GCREF, B())), + (token1, rffi.cast(llmemory.GCREF, C())), + + (token2, rffi.cast(llmemory.GCREF, A())), + (token2, rffi.cast(llmemory.GCREF, B())), + (token2, rffi.cast(llmemory.GCREF, C())), + (token2, rffi.cast(llmemory.GCREF, [42, 43])), + + (token3, rffi.cast(llmemory.GCREF, A())), + (token3, rffi.cast(llmemory.GCREF, B())), + (token3, rffi.cast(llmemory.GCREF, [44, 45])), + ]: + frame = execute_token(token, p0) + descr = cpu.get_latest_descr(frame) + if descr is finaldescr: + print 'match' + elif descr is faildescr: + print 'fail' + else: + print '???' + + call_initial_function(t, g) + + cbuilder = genc.CStandaloneBuilder(t, main, t.config) + cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) + cbuilder.compile() + + data = cbuilder.cmdexec('') + assert data == ('fail\n' + 'match\n' + 'fail\n' + + 'fail\n' + 'match\n' + 'fail\n' + 'fail\n' + + 'match\n' + 'match\n' + 'fail\n') + + +def test_guards_translated_with_gctypeptr(): + run_guards_translated(gcremovetypeptr=False) + +def test_guards_translated_without_gctypeptr(): + run_guards_translated(gcremovetypeptr=True) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1741,25 +1741,10 @@ if offset is not None: self.mc.CMP(mem(loc_ptr, offset), loc_classptr) else: - # XXX hard-coded assumption: to go from an object to its class - # we use the following algorithm: - # - read the typeid from mem(locs[0]), i.e. at offset 0; - # this is a complete word (N=4 bytes on 32-bit, N=8 on - # 64-bits) - # - keep the lower half of what is read there (i.e. - # truncate to an unsigned 'N / 2' bytes value) - # - multiply by 4 (on 32-bits only) and use it as an - # offset in type_info_group - # - add 16/32 bytes, to go past the TYPE_INFO structure assert isinstance(loc_classptr, ImmedLoc) classptr = loc_classptr.value - # here, we have to go back from 'classptr' to the value expected - # from reading the half-word in the object header. - from rpython.memory.gctypelayout import GCData - sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) - expected_typeid = classptr - sizeof_ti - type_info_group + expected_typeid = (self.cpu.gc_ll_descr + .get_typeid_from_classptr_if_gcremovetypeptr(classptr)) self._cmp_guard_gc_type(loc_ptr, ImmedLoc(expected_typeid)) def _cmp_guard_gc_type(self, loc_ptr, loc_expected_typeid): @@ -1795,6 +1780,23 @@ self._cmp_guard_gc_type(locs[0], locs[1]) self.implement_guard(guard_token, 'NE') + def genop_guard_guard_is_object(self, ign_1, guard_op, + guard_token, locs, ign_2): + assert self.cpu.supports_guard_gc_type + [loc_object, loc_typeid] = locs + # idea: read the typeid, fetch the field 'infobits' from the big + # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + base_type_info, shift_by, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + if IS_X86_32: + self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) + else: + self.mc.MOV32(loc_typeid, mem(loc_object, 0)) + loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) + self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) + # + self.implement_guard(guard_token, 'Z') + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): exc = (guard_opnum == rop.GUARD_EXCEPTION or diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -431,10 +431,14 @@ consider_guard_gc_type = consider_guard_class def consider_guard_is_object(self, op): - xxx + x = self.make_sure_var_in_reg(op.getarg(0)) + tmp_box = TempVar() + y = self.rm.force_allocate_reg(tmp_box) + self.rm.possibly_free_var(tmp_box) + self.perform_guard(op, [x, y], None) def consider_guard_subclass(self, op): - xxx + assert 0 # xxx def _consider_binop_part(self, op, symm=False): x = op.getarg(0) @@ -798,6 +802,7 @@ def _consider_real_call(self, op): effectinfo = op.getdescr().get_extra_info() + assert effectinfo is not None oopspecindex = effectinfo.oopspecindex if oopspecindex != EffectInfo.OS_NONE: if IS_X86_32: diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -674,6 +674,9 @@ TEST8_bi = insn(rex_nw, '\xF6', orbyte(0<<3), stack_bp(1), immediate(2, 'b')) TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') + TEST_ai = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_scaled_reg_plus_const(1), immediate(2)) + TEST_mi = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_const(1), immediate(2)) + TEST_ji = insn(rex_w, '\xF7', orbyte(0<<3), abs_(1), immediate(2)) BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1)) BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_(1)) From noreply at buildbot.pypy.org Fri Sep 4 13:40:57 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 13:40:57 +0200 (CEST) Subject: [pypy-commit] cffi default: unbalanced parens Message-ID: <20150904114057.CB7921C0207@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2268:f34ac1df2d5e Date: 2015-09-04 13:41 +0200 http://bitbucket.org/cffi/cffi/changeset/f34ac1df2d5e/ Log: unbalanced parens diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -200,7 +200,7 @@ The ``ffi.cdef()`` call takes an optional argument ``packed``: if True, then all structs declared within -this cdef are "packed". If you need both packed and non-packed +this cdef are "packed". (If you need both packed and non-packed structs, use several cdefs in sequence.) This has a meaning similar to ``__attribute__((packed))`` in GCC. It specifies that all structure fields should have an alignment of one From noreply at buildbot.pypy.org Fri Sep 4 13:42:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 13:42:46 +0200 (CEST) Subject: [pypy-commit] cffi default: fix textual reference Message-ID: <20150904114246.7E4BB1C0362@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2269:9b9b28de48be Date: 2015-09-04 13:43 +0200 http://bitbucket.org/cffi/cffi/changeset/9b9b28de48be/ Log: fix textual reference diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -206,8 +206,8 @@ specifies that all structure fields should have an alignment of one byte. (Note that the packed attribute has no effect on bit fields so far, which mean that they may be packed differently than on GCC. -Also, this has no effect on structs declared with ``"...;"``---next -section.) +Also, this has no effect on structs declared with ``"...;"``---more +about it later in `Letting the C compiler fill the gaps`_.) .. _`ffi.set_unicode()`: From noreply at buildbot.pypy.org Fri Sep 4 14:14:36 2015 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 4 Sep 2015 14:14:36 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: more fixes for issue #2055 (Christian Clauss) Message-ID: <20150904121436.45E401C12D6@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: extradoc Changeset: r633:51c1452f8036 Date: 2015-09-04 15:15 +0300 http://bitbucket.org/pypy/pypy.org/changeset/51c1452f8036/ Log: more fixes for issue #2055 (Christian Clauss) diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -72,7 +72,7 @@

    PyPy is a replacement for CPython. It is built using the RPython language that was co-developed with it. The main reason to use it instead of CPython is speed: it runs generally faster (see next section).

    -

    PyPy 2.5 implements Python 2.7.10 and runs on Intel +

    PyPy implements Python 2.7.10 and runs on Intel x86 (IA-32) , x86_64 and ARM platforms, with PPC being stalled. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -10,7 +10,7 @@ language that was co-developed with it. The main reason to use it instead of CPython is speed: it runs generally faster (see next section). -**PyPy 2.5** implements **Python 2.7.10** and runs on Intel +**PyPy** implements **Python 2.7.10** and runs on Intel `x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms, with PPC being stalled. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python From noreply at buildbot.pypy.org Fri Sep 4 14:54:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 14:54:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue #2133: accept unicodes in these curses functions (and convert them Message-ID: <20150904125423.6775C1C2059@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79418:6e21389526e8 Date: 2015-09-04 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/6e21389526e8/ Log: Issue #2133: accept unicodes in these curses functions (and convert them to ascii string), like CPython does. diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py --- a/lib_pypy/_curses.py +++ b/lib_pypy/_curses.py @@ -1026,16 +1026,22 @@ def tigetflag(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetflag(capname) def tigetnum(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetnum(capname) def tigetstr(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') val = lib.tigetstr(capname) if int(ffi.cast("intptr_t", val)) in (0, -1): return None From noreply at buildbot.pypy.org Fri Sep 4 15:06:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 15:06:36 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Implement and test guard_subclass. Message-ID: <20150904130636.C588A1C207C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79419:17252241ecf0 Date: 2015-09-04 14:09 +0100 http://bitbucket.org/pypy/pypy/changeset/17252241ecf0/ Log: Implement and test guard_subclass. diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -693,6 +693,17 @@ expected_typeid >>= 2 return expected_typeid + def get_translated_info_for_typeinfo(self): + from rpython.memory.gctypelayout import GCData + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + if WORD == 4: + shift_by = 2 + elif WORD == 8: + shift_by = 0 + sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) + return (type_info_group, shift_by, sizeof_ti) + def _setup_guard_is_object(self): from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, @@ -700,16 +711,8 @@ self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE def get_translated_info_for_guard_is_object(self): - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) - if WORD == 4: - shift_by = 2 - elif WORD == 8: - shift_by = 0 - return (type_info_group + infobits_offset, - shift_by, - self._T_IS_RPYTHON_INSTANCE) + return (infobits_offset, self._T_IS_RPYTHON_INSTANCE) # ____________________________________________________________ diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -54,6 +54,8 @@ self.vtable_offset, _ = symbolic.get_field_token(rclass.OBJECT, 'typeptr', translate_support_code) + self.subclassrange_min_offset, _ = symbolic.get_field_token( + rclass.OBJECT_VTABLE, 'subclassrange_min', translate_support_code) if translate_support_code: self._setup_exception_handling_translated() else: diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py --- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -72,14 +72,24 @@ """, namespace={'finaldescr': finaldescr, 'faildescr': faildescr}) + loop4 = parse(""" + [p0] + guard_subclass(p0, ConstInt(vtable_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, + 'vtable_B': vtable_B}) + def g(): cpu.setup_once() token1 = JitCellToken() token2 = JitCellToken() token3 = JitCellToken() + token4 = JitCellToken() cpu.compile_loop(loop1.inputargs, loop1.operations, token1) cpu.compile_loop(loop2.inputargs, loop2.operations, token2) cpu.compile_loop(loop3.inputargs, loop3.operations, token3) + cpu.compile_loop(loop4.inputargs, loop4.operations, token4) for token, p0 in [ (token1, rffi.cast(llmemory.GCREF, A())), @@ -94,6 +104,10 @@ (token3, rffi.cast(llmemory.GCREF, A())), (token3, rffi.cast(llmemory.GCREF, B())), (token3, rffi.cast(llmemory.GCREF, [44, 45])), + + (token4, rffi.cast(llmemory.GCREF, A())), + (token4, rffi.cast(llmemory.GCREF, B())), + (token4, rffi.cast(llmemory.GCREF, C())), ]: frame = execute_token(token, p0) descr = cpu.get_latest_descr(frame) @@ -122,7 +136,11 @@ 'match\n' 'match\n' - 'fail\n') + 'fail\n' + + 'fail\n' + 'match\n' + 'match\n') def test_guards_translated_with_gctypeptr(): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -11,6 +11,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref +from rpython.rtyper import rclass from rpython.rlib.jit import AsmInfo from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs, @@ -1786,17 +1787,58 @@ [loc_object, loc_typeid] = locs # idea: read the typeid, fetch the field 'infobits' from the big # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. - base_type_info, shift_by, IS_OBJECT_FLAG = ( - self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) if IS_X86_32: self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) else: self.mc.MOV32(loc_typeid, mem(loc_object, 0)) - loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) + # + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + infobits_offset, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + loc_infobits = addr_add(imm(base_type_info), loc_typeid, + scale=shift_by, offset=infobits_offset) self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) # self.implement_guard(guard_token, 'Z') + def genop_guard_guard_subclass(self, op, guard_op, + guard_token, locs, ign_2): + assert self.cpu.supports_guard_gc_type + [loc_object, loc_check_against_class, loc_tmp] = locs + assert isinstance(loc_object, RegLoc) + assert isinstance(loc_tmp, RegLoc) + offset = self.cpu.vtable_offset + offset2 = self.cpu.subclassrange_min_offset + if offset is not None: + # read this field to get the vtable pointer + self.mc.MOV_rm(loc_tmp.value, (loc_object.value, offset)) + # read the vtable's subclassrange_min field + self.mc.MOV_rm(loc_tmp.value, (loc_tmp.value, offset2)) + else: + # read the typeid + if IS_X86_32: + self.mc.MOVZX16(loc_tmp, mem(loc_object, 0)) + else: + self.mc.MOV32(loc_tmp, mem(loc_object, 0)) + # read the vtable's subclassrange_min field, as a single + # step with the correct offset + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + self.mc.MOV(loc_tmp, addr_add(imm(base_type_info), loc_tmp, + scale = shift_by, + offset = sizeof_ti + offset2)) + # get the two bounds to check against + vtable_ptr = loc_check_against_class.getint() + vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) + check_min = vtable_ptr.subclassrange_min + check_max = vtable_ptr.subclassrange_max + # check by doing the unsigned comparison (tmp - min) < (max - min) + self.mc.SUB_ri(loc_tmp.value, check_min) + self.mc.CMP_ri(loc_tmp.value, check_max - check_min) + # the guard fails if we get a "not below" result + self.implement_guard(guard_token, 'NB') + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): exc = (guard_opnum == rop.GUARD_EXCEPTION or diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -438,7 +438,12 @@ self.perform_guard(op, [x, y], None) def consider_guard_subclass(self, op): - assert 0 # xxx + x = self.make_sure_var_in_reg(op.getarg(0)) + y = self.loc(op.getarg(1)) + tmp_box = TempVar() + z = self.rm.force_allocate_reg(tmp_box) + self.rm.possibly_free_var(tmp_box) + self.perform_guard(op, [x, y, z], None) def _consider_binop_part(self, op, symm=False): x = op.getarg(0) From noreply at buildbot.pypy.org Fri Sep 4 15:22:45 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:22:45 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix recursion here, that should finish all of metainterp/test Message-ID: <20150904132245.22EC21C140E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79420:50446eeb623f Date: 2015-09-04 15:22 +0200 http://bitbucket.org/pypy/pypy/changeset/50446eeb623f/ Log: fix recursion here, that should finish all of metainterp/test 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 @@ -105,8 +105,6 @@ self.S = S self._vtable = vtable self._is_object = bool(vtable) - self.all_fielddescrs = heaptracker.all_fielddescrs(runner, S, - get_field_descr=LLGraphCPU.fielddescrof) self._runner = runner def get_all_fielddescrs(self): @@ -443,6 +441,8 @@ except KeyError: descr = SizeDescr(S, vtable, self) self.descrs[key] = descr + descr.all_fielddescrs = heaptracker.all_fielddescrs(self, S, + get_field_descr=LLGraphCPU.fielddescrof) if descr._is_object and vtable is not Ellipsis: assert vtable heaptracker.testing_gcstruct2vtable.setdefault(S, vtable) From noreply at buildbot.pypy.org Fri Sep 4 15:22:47 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:22:47 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150904132247.44B371C140E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79421:a2668c2f5ddf Date: 2015-09-04 15:22 +0200 http://bitbucket.org/pypy/pypy/changeset/a2668c2f5ddf/ Log: merge diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -693,6 +693,17 @@ expected_typeid >>= 2 return expected_typeid + def get_translated_info_for_typeinfo(self): + from rpython.memory.gctypelayout import GCData + type_info_group = llop.gc_get_type_info_group(llmemory.Address) + type_info_group = rffi.cast(lltype.Signed, type_info_group) + if WORD == 4: + shift_by = 2 + elif WORD == 8: + shift_by = 0 + sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) + return (type_info_group, shift_by, sizeof_ti) + def _setup_guard_is_object(self): from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, @@ -700,16 +711,8 @@ self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE def get_translated_info_for_guard_is_object(self): - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) - if WORD == 4: - shift_by = 2 - elif WORD == 8: - shift_by = 0 - return (type_info_group + infobits_offset, - shift_by, - self._T_IS_RPYTHON_INSTANCE) + return (infobits_offset, self._T_IS_RPYTHON_INSTANCE) # ____________________________________________________________ diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -54,6 +54,8 @@ self.vtable_offset, _ = symbolic.get_field_token(rclass.OBJECT, 'typeptr', translate_support_code) + self.subclassrange_min_offset, _ = symbolic.get_field_token( + rclass.OBJECT_VTABLE, 'subclassrange_min', translate_support_code) if translate_support_code: self._setup_exception_handling_translated() else: diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py --- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -72,14 +72,24 @@ """, namespace={'finaldescr': finaldescr, 'faildescr': faildescr}) + loop4 = parse(""" + [p0] + guard_subclass(p0, ConstInt(vtable_B), descr=faildescr) [] + finish(descr=finaldescr) + """, namespace={'finaldescr': finaldescr, + 'faildescr': faildescr, + 'vtable_B': vtable_B}) + def g(): cpu.setup_once() token1 = JitCellToken() token2 = JitCellToken() token3 = JitCellToken() + token4 = JitCellToken() cpu.compile_loop(loop1.inputargs, loop1.operations, token1) cpu.compile_loop(loop2.inputargs, loop2.operations, token2) cpu.compile_loop(loop3.inputargs, loop3.operations, token3) + cpu.compile_loop(loop4.inputargs, loop4.operations, token4) for token, p0 in [ (token1, rffi.cast(llmemory.GCREF, A())), @@ -94,6 +104,10 @@ (token3, rffi.cast(llmemory.GCREF, A())), (token3, rffi.cast(llmemory.GCREF, B())), (token3, rffi.cast(llmemory.GCREF, [44, 45])), + + (token4, rffi.cast(llmemory.GCREF, A())), + (token4, rffi.cast(llmemory.GCREF, B())), + (token4, rffi.cast(llmemory.GCREF, C())), ]: frame = execute_token(token, p0) descr = cpu.get_latest_descr(frame) @@ -122,7 +136,11 @@ 'match\n' 'match\n' - 'fail\n') + 'fail\n' + + 'fail\n' + 'match\n' + 'match\n') def test_guards_translated_with_gctypeptr(): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -11,6 +11,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref +from rpython.rtyper import rclass from rpython.rlib.jit import AsmInfo from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs, @@ -1786,17 +1787,58 @@ [loc_object, loc_typeid] = locs # idea: read the typeid, fetch the field 'infobits' from the big # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. - base_type_info, shift_by, IS_OBJECT_FLAG = ( - self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) if IS_X86_32: self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) else: self.mc.MOV32(loc_typeid, mem(loc_object, 0)) - loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by) + # + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + infobits_offset, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + loc_infobits = addr_add(imm(base_type_info), loc_typeid, + scale=shift_by, offset=infobits_offset) self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) # self.implement_guard(guard_token, 'Z') + def genop_guard_guard_subclass(self, op, guard_op, + guard_token, locs, ign_2): + assert self.cpu.supports_guard_gc_type + [loc_object, loc_check_against_class, loc_tmp] = locs + assert isinstance(loc_object, RegLoc) + assert isinstance(loc_tmp, RegLoc) + offset = self.cpu.vtable_offset + offset2 = self.cpu.subclassrange_min_offset + if offset is not None: + # read this field to get the vtable pointer + self.mc.MOV_rm(loc_tmp.value, (loc_object.value, offset)) + # read the vtable's subclassrange_min field + self.mc.MOV_rm(loc_tmp.value, (loc_tmp.value, offset2)) + else: + # read the typeid + if IS_X86_32: + self.mc.MOVZX16(loc_tmp, mem(loc_object, 0)) + else: + self.mc.MOV32(loc_tmp, mem(loc_object, 0)) + # read the vtable's subclassrange_min field, as a single + # step with the correct offset + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + self.mc.MOV(loc_tmp, addr_add(imm(base_type_info), loc_tmp, + scale = shift_by, + offset = sizeof_ti + offset2)) + # get the two bounds to check against + vtable_ptr = loc_check_against_class.getint() + vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) + check_min = vtable_ptr.subclassrange_min + check_max = vtable_ptr.subclassrange_max + # check by doing the unsigned comparison (tmp - min) < (max - min) + self.mc.SUB_ri(loc_tmp.value, check_min) + self.mc.CMP_ri(loc_tmp.value, check_max - check_min) + # the guard fails if we get a "not below" result + self.implement_guard(guard_token, 'NB') + def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): exc = (guard_opnum == rop.GUARD_EXCEPTION or diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -438,7 +438,12 @@ self.perform_guard(op, [x, y], None) def consider_guard_subclass(self, op): - assert 0 # xxx + x = self.make_sure_var_in_reg(op.getarg(0)) + y = self.loc(op.getarg(1)) + tmp_box = TempVar() + z = self.rm.force_allocate_reg(tmp_box) + self.rm.possibly_free_var(tmp_box) + self.perform_guard(op, [x, y, z], None) def _consider_binop_part(self, op, symm=False): x = op.getarg(0) From noreply at buildbot.pypy.org Fri Sep 4 15:54:05 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:54:05 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: skip one test Message-ID: <20150904135405.350521C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79422:2ff84caf5440 Date: 2015-09-04 15:25 +0200 http://bitbucket.org/pypy/pypy/changeset/2ff84caf5440/ Log: skip one test 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 @@ -8165,6 +8165,8 @@ self.optimize_loop(ops, expected) def test_exploding_duplication(self): + py.test.skip("maybe we want to revisit this guy, but in the new model" + " it fails for same_as reasons") ops = """ [i1, i2] i3 = int_add(i1, i1) From noreply at buildbot.pypy.org Fri Sep 4 15:54:07 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:54:07 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: port the rudimentary direct tests Message-ID: <20150904135407.3B2BC1C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79423:a6fdf07f72ea Date: 2015-09-04 15:32 +0200 http://bitbucket.org/pypy/pypy/changeset/a6fdf07f72ea/ Log: port the rudimentary direct tests diff --git a/rpython/jit/metainterp/optimizeopt/test/test_short.py b/rpython/jit/metainterp/optimizeopt/test/test_short.py --- a/rpython/jit/metainterp/optimizeopt/test/test_short.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_short.py @@ -27,39 +27,21 @@ i1 = InputArgInt() op = ResOperation(rop.INT_ADD, [i0, i1]) sb = ShortBoxes() - short_boxes = sb.create_short_boxes(Opt([op]), [i0, i1]) - assert short_boxes == [(op, None)] + short_boxes = sb.create_short_boxes(Opt([op]), [i0, i1], [i0, i1]) + assert len(short_boxes) == 3 + short_boxes.sort(key=str) + # inputarg + assert short_boxes[0].short_op.res is i0 + assert short_boxes[0].preamble_op is sb.short_inputargs[0] + # pure op + assert short_boxes[2].preamble_op.getarg(0) is sb.short_inputargs[0] + assert short_boxes[2].short_op.res is op def test_pure_ops_does_not_work(self): i0 = InputArgInt() i1 = InputArgInt() op = ResOperation(rop.INT_ADD, [i0, i1]) sb = ShortBoxes() - short_boxes = sb.create_short_boxes(Opt([op]), [i0]) - assert short_boxes == [] + short_boxes = sb.create_short_boxes(Opt([op]), [i0], [i0]) + assert len(short_boxes) == 1 # just inparg - def test_multiple_similar_ops(self): - """ This can happen e.g. if heap cache and pure ops produce - the same thing. So let's say we have: - - i0 = int_add(i0, 1) - setfield_gc(p0, i0) - - now i0 can be gotten in two ways - from getfield or from int_add, - we store both in short preamble (in case someone else who inlines - the short preamble does not share them) - """ - py.test.skip("l8r") - i0 = InputArgInt() - i1 = InputArgInt() - op = ResOperation(rop.INT_ADD, [i0, i1]) - op1 = ResOperation(rop.GETFIELD_GC_I, [i0], descr=Descr()) - sb = ShortBoxes() - sb.create_short_boxes(Opt([op, (op, op1)]), [i0, i1]) - assert len(sb.short_boxes) == 2 - l = [x.getopnum() for x, _ in sb.short_boxes] - l.sort() - assert l == [rop.INT_ADD, rop.SAME_AS_I] - assert [x for x, y in sb.short_boxes][0] == op - assert [y for x, y in sb.short_boxes] == [op, op1] - From noreply at buildbot.pypy.org Fri Sep 4 15:54:09 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:54:09 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: post test_unroll Message-ID: <20150904135409.6C4451C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79424:9a6b88a2d07c Date: 2015-09-04 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/9a6b88a2d07c/ Log: post test_unroll diff --git a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py --- a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py @@ -10,7 +10,7 @@ from rpython.jit.metainterp.history import (TreeLoop, ConstInt, JitCellToken, TargetToken) from rpython.jit.metainterp.resoperation import rop, ResOperation,\ - InputArgRef + InputArgRef, InputArgInt from rpython.jit.metainterp.optimizeopt.shortpreamble import \ ShortPreambleBuilder, PreambleOp, ShortInputArg from rpython.jit.metainterp.compile import LoopCompileData @@ -23,9 +23,15 @@ class FakeOptimizer(object): optearlyforce = None + class cpu: + remove_gctypeptr = True + def getptrinfo(self, box): return box.get_forwarded() + def setinfo_from_preamble(self, *args): + pass + def get_box_replacement(self, box): return box @@ -83,9 +89,7 @@ assert vs.make_inputargs([1], FakeOptimizer()) == [] assert vs.state[0].level == LEVEL_CONSTANT # we have exported values for i1, which happens to be an inputarg - assert es.inputarg_mapping[0][1].getint() == 1 - assert isinstance(es.inputarg_mapping[0][1], ConstInt) - sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, + sb = ShortPreambleBuilder([], es.short_boxes, es.short_inputargs, es.exported_infos) sp = sb.build_short_preamble() exp = """ @@ -116,7 +120,10 @@ assert isinstance(vs.state[0], NotVirtualStateInfo) assert vs.state[0].level == LEVEL_UNKNOWN op = preamble.operations[0] - assert es.short_boxes[0].short_op.res is op + short_boxes = [box for box in es.short_boxes + if not isinstance(box.short_op, ShortInputArg)] + assert len(short_boxes) == 1 + assert short_boxes[0].short_op.res is op def test_guard_class(self): loop = """ @@ -134,47 +141,47 @@ def test_virtual(self): loop = """ - [p1, p2] - p0 = new_with_vtable(descr=nodesize) - setfield_gc(p0, 1, descr=valuedescr) - setfield_gc(p0, p1, descr=nextdescr) - jump(p0, p0) + [p1, p2, i3] + p0 = new_with_vtable(descr=simpledescr) + setfield_gc(p0, i3, descr=simplevalue) + jump(p0, p0, i3) """ es, loop, preamble = self.optimize(loop) vs = es.virtual_state assert vs.state[0] is vs.state[1] assert isinstance(vs.state[0], VirtualStateInfo) assert isinstance(vs.state[0].fieldstate[0], NotVirtualStateInfo) - assert vs.state[0].fieldstate[0].level == LEVEL_CONSTANT - assert isinstance(vs.state[0].fieldstate[3], NotVirtualStateInfo) - assert vs.state[0].fieldstate[3].level == LEVEL_UNKNOWN + assert vs.state[0].fieldstate[0].level == LEVEL_UNKNOWN assert vs.numnotvirtuals == 1 p = InputArgRef() - py.test.raises(BadVirtualState, vs.make_inputargs, [p, p], - FakeOptimizer()) - ptrinfo = info.StructPtrInfo(self.nodesize) - p2 = InputArgRef() - ptrinfo._fields = [None, None, None, p2] + i = InputArgInt() + ptrinfo = info.StructPtrInfo(self.nodesize, is_virtual=True) + ptrinfo._fields = [i] p.set_forwarded(ptrinfo) - vs.make_inputargs([p, p], FakeOptimizer()) + vs.make_inputargs([p, p, i], FakeOptimizer()) - def test_short_boxes_heapcache(self): + def test_short_boxes_heapcache(self): loop = """ [p0, i1] i0 = getfield_gc_i(p0, descr=valuedescr) - jump(p0, i0) + jump(p0, i1) """ es, loop, preamble = self.optimize(loop) op = preamble.operations[0] - assert len(es.short_boxes) == 1 - assert es.short_boxes[0].short_op.res is op - sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, - es.exported_infos) + short_boxes = [box for box in es.short_boxes + if not isinstance(box.short_op, ShortInputArg)] + assert len(short_boxes) == 1 + assert short_boxes[0].short_op.res is op + sb = ShortPreambleBuilder(loop.inputargs, + es.short_boxes, es.short_inputargs, + es.exported_infos, FakeOptimizer()) op = preamble.operations[0] - short_op = sb.use_box(op) - sb.add_preamble_op(PreambleOp(op, short_op)) + short_op = sb.use_box(op, short_boxes[0].preamble_op, FakeOptimizer()) + sb.add_preamble_op(PreambleOp(op, short_op, False)) exp_short = """ [p0, i1] + guard_nonnull(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] i0 = getfield_gc_i(p0, descr=valuedescr) jump(i0) """ @@ -189,7 +196,9 @@ """ es, loop, preamble = self.optimize(loop) op = preamble.operations[0] - assert es.short_boxes[0].short_op.res is op + short_boxes = [box for box in es.short_boxes + if not isinstance(box.short_op, ShortInputArg)] + assert short_boxes[0].short_op.res is op assert es.exported_infos[op].is_constant() def test_only_setfield(self): @@ -201,10 +210,12 @@ """ es, loop, preamble = self.optimize(loop) p0, p1 = es.short_inputargs - assert es.short_boxes[0].short_op.res.getint() == 5 - assert es.short_boxes[1].short_op.res.getint() == 5 - assert es.short_boxes[0].preamble_op.getarg(0) is p0 - assert es.short_boxes[1].preamble_op.getarg(0) is p1 + short_boxes = [box for box in es.short_boxes + if not isinstance(box.short_op, ShortInputArg)] + assert short_boxes[0].short_op.res.getint() == 5 + assert short_boxes[1].short_op.res.getint() == 5 + assert short_boxes[0].preamble_op.getarg(0) is p0 + assert short_boxes[1].preamble_op.getarg(0) is p1 def test_double_getfield_plus_pure(self): loop = """ @@ -216,7 +227,7 @@ jump(p0) """ es, loop, preamble = self.optimize(loop) - assert len(es.short_boxes) == 3 + assert len(es.short_boxes) == 4 # both getfields are available as # well as getfield_gc_pure @@ -233,8 +244,7 @@ jump(i1, p1, p2) """ es, loop, preamble = self.optimize(loop) - assert len(producable_short_boxes(es.short_boxes)) == 2 - xxx + assert len(producable_short_boxes(es.short_boxes)) == 1 def test_setfield_forced_virtual(self): loop = """ @@ -245,30 +255,23 @@ jump(p2, p3) """ es, loop, preamble = self.optimize(loop) - sb = ShortPreambleBuilder(es.short_boxes, es.short_inputargs, + sb = ShortPreambleBuilder(loop.inputargs, es.short_boxes, + es.short_inputargs, es.exported_infos) - assert len(sb.producable_ops) == 1 - op = sb.producable_ops.keys()[0] - pop = sb.use_box(op) - sb.add_preamble_op(PreambleOp(op, pop)) + short_boxes = [box for box in es.short_boxes + if not isinstance(box.short_op, ShortInputArg)] + op = short_boxes[0].short_op.res + pop = sb.use_box(op, short_boxes[0].preamble_op, FakeOptimizer()) + sb.add_preamble_op(PreambleOp(op, pop, False)) exp_short = """ - [p0] + [p0, p1] + guard_nonnull(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] i1 = getfield_gc_i(p0, descr=valuedescr) jump(i1) """ self.compare_short(sb.build_short_preamble(), exp_short) - def test_no_short_boxes(self): - loop = """ - [p0, p1] - p2 = escape_r(p0) - p3 = escape_r(p1) - setfield_gc(p2, p3, descr=nextdescr) - jump(p2, p3) - """ - es, loop, preamble = self.optimize(loop) - assert not es.short_boxes - def test_loopinvariant(self): loop = """ [i1] @@ -278,7 +281,7 @@ jump(i1) """ es, loop, preamble = self.optimize(loop) - assert len(es.short_boxes) == 1 + assert len(es.short_boxes) == 2 def test_circular_force(self): ops = """ From noreply at buildbot.pypy.org Fri Sep 4 15:54:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 15:54:50 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: Use a pipe into "less" to scroll if the output is longer than one screen. Message-ID: <20150904135450.2E7501C1458@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: stmgc-c8-gcc Changeset: r79425:81299ae4c066 Date: 2015-09-04 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/81299ae4c066/ Log: Use a pipe into "less" to scroll if the output is longer than one screen. diff --git a/pypy/stm/print_stm_log.py b/pypy/stm/print_stm_log.py --- a/pypy/stm/print_stm_log.py +++ b/pypy/stm/print_stm_log.py @@ -1,5 +1,5 @@ #!/usr/bin/env pypy -import sys +import sys, os import struct, re, linecache # ____________________________________________________________ @@ -389,4 +389,9 @@ return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + if sys.stdout.isatty(): + sys.stdout = os.popen("less --quit-if-one-screen", "w") + try: + sys.exit(main(sys.argv[1:])) + finally: + sys.stdout.close() From noreply at buildbot.pypy.org Fri Sep 4 15:55:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 15:55:14 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: uh info can be none Message-ID: <20150904135514.C462E1C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79426:efa4c8b64632 Date: 2015-09-04 15:55 +0200 http://bitbucket.org/pypy/pypy/changeset/efa4c8b64632/ Log: uh info can be none diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -178,9 +178,10 @@ def enum_forced_boxes(self, boxes, box, optimizer, force_boxes=False): box = optimizer.get_box_replacement(box) info = optimizer.getptrinfo(box) - assert isinstance(info, AbstractStructPtrInfo) if info is None or not info.is_virtual(): raise BadVirtualState() + else: + assert isinstance(info, AbstractStructPtrInfo) for i in range(len(self.fielddescrs)): state = self.fieldstate[i] if not state: From noreply at buildbot.pypy.org Fri Sep 4 16:12:06 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 4 Sep 2015 16:12:06 +0200 (CEST) Subject: [pypy-commit] pypy memoryerror: close branch Message-ID: <20150904141206.517161C0207@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: memoryerror Changeset: r79427:078a0334c34d Date: 2015-09-04 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/078a0334c34d/ Log: close branch From noreply at buildbot.pypy.org Fri Sep 4 16:12:08 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 4 Sep 2015 16:12:08 +0200 (CEST) Subject: [pypy-commit] pypy memoryerror2: close branch Message-ID: <20150904141208.56FC51C0207@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: memoryerror2 Changeset: r79428:10cb9ba203a9 Date: 2015-09-04 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/10cb9ba203a9/ Log: close branch From noreply at buildbot.pypy.org Fri Sep 4 16:12:10 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 4 Sep 2015 16:12:10 +0200 (CEST) Subject: [pypy-commit] pypy memoryerror3: close branch Message-ID: <20150904141210.7BCEF1C0207@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: memoryerror3 Changeset: r79429:f693472e325f Date: 2015-09-04 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/f693472e325f/ Log: close branch From noreply at buildbot.pypy.org Fri Sep 4 16:27:33 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 16:27:33 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: add a case for we don't know Message-ID: <20150904142733.1D6E41C1FA5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79430:d68f64dcc8cb Date: 2015-09-04 16:27 +0200 http://bitbucket.org/pypy/pypy/changeset/d68f64dcc8cb/ Log: add a case for we don't know 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 @@ -239,6 +239,9 @@ shortboxes): if self._fields is None: return + if descr.get_index() >= len(self._fields): + # we don't know about this item + return op = optimizer.get_box_replacement(self._fields[descr.get_index()]) opnum = OpHelpers.getfield_for_descr(descr) getfield_op = ResOperation(opnum, [structbox], descr=descr) @@ -541,6 +544,9 @@ shortboxes): if self._items is None: return + if index >= len(self._items): + # we don't know about this item + return item = self._items[index] if item is not None: op = optimizer.get_box_replacement(item) From noreply at buildbot.pypy.org Fri Sep 4 17:09:38 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 17:09:38 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: let's just use one exception instead of two that have to be caught a bit everywhere' Message-ID: <20150904150938.A480A1C0207@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79431:3c1f7d42f12b Date: 2015-09-04 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/3c1f7d42f12b/ Log: let's just use one exception instead of two that have to be caught a bit everywhere' diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -13,9 +13,6 @@ LEVEL_KNOWNCLASS = '\x02' LEVEL_CONSTANT = '\x03' -class BadVirtualState(Exception): - pass - class VirtualStatesCantMatch(Exception): def __init__(self, msg='?', state=None): self.msg = msg @@ -179,7 +176,7 @@ box = optimizer.get_box_replacement(box) info = optimizer.getptrinfo(box) if info is None or not info.is_virtual(): - raise BadVirtualState() + raise VirtualStatesCantMatch() else: assert isinstance(info, AbstractStructPtrInfo) for i in range(len(self.fielddescrs)): @@ -254,9 +251,9 @@ box = optimizer.get_box_replacement(box) info = optimizer.getptrinfo(box) if info is None or not info.is_virtual(): - raise BadVirtualState() + raise VirtualStatesCantMatch() if len(self.fieldstate) > info.getlength(): - raise BadVirtualState + raise VirtualStatesCantMatch for i in range(len(self.fieldstate)): fieldbox = info.getitem(self.arraydescr, i) s = self.fieldstate[i] @@ -321,11 +318,11 @@ def enum_forced_boxes(self, boxes, box, optimizer, force_boxes=False): opinfo = optimizer.getptrinfo(box) if not isinstance(opinfo, ArrayStructInfo): - raise BadVirtualState + raise VirtualStatesCantMatch if not opinfo.is_virtual(): - raise BadVirtualState + raise VirtualStatesCantMatch #if len(self.fielddescrs) > len(value._items): - # raise BadVirtualState + # raise VirtualStatesCantMatch for i in range(self.length): for descr in self.fielddescrs: index = i * len(self.fielddescrs) + descr.get_index() @@ -334,7 +331,7 @@ descr.get_index()] if fieldstate is None: if itembox is not None: - raise BadVirtualState + raise VirtualStatesCantMatch continue # I think itembox must be present here if fieldstate.position > self.position: @@ -501,7 +498,7 @@ if force_boxes: info.force_box(box, optimizer) else: - raise BadVirtualState + raise VirtualStatesCantMatch boxes[self.position_in_notvirtuals] = box def _enum(self, virtual_state): From noreply at buildbot.pypy.org Fri Sep 4 17:25:16 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 17:25:16 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: port some of test_virtualstate Message-ID: <20150904152516.D5F781C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79432:83da4c5584bd Date: 2015-09-04 17:24 +0200 http://bitbucket.org/pypy/pypy/changeset/83da4c5584bd/ Log: port some of test_virtualstate diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -21,7 +21,8 @@ from rpython.jit.metainterp.optimizeopt import info class FakeOptimizer(Optimizer): - def __init__(self): + def __init__(self, cpu): + self.cpu = cpu self.optearlyforce = None class BaseTestGenerateGuards(BaseTest): @@ -29,7 +30,7 @@ if inputargs is None: inputargs = [box] info1.position = info2.position = 0 - state = GenerateGuardState(self.cpu) + state = GenerateGuardState(FakeOptimizer(self.cpu)) info1.generate_guards(info2, box, opinfo, state) self.compare(state.extra_guards, expected, inputargs) @@ -51,7 +52,7 @@ if info2.position == -1: info2.position = 0 if state is None: - state = GenerateGuardState(self.cpu) + state = GenerateGuardState(FakeOptimizer(self.cpu)) info1.generate_guards(info2, box, opinfo, state) assert not state.extra_guards return state @@ -62,12 +63,12 @@ if info2.position == -1: info2.position = 0 if state is None: - state = GenerateGuardState(self.cpu) + state = GenerateGuardState(FakeOptimizer(self.cpu)) with py.test.raises(VirtualStatesCantMatch): info1.generate_guards(info2, box, opinfo, state) def test_make_inputargs(self): - optimizer = FakeOptimizer() + optimizer = FakeOptimizer(self.cpu) args = [InputArgInt()] info0 = NotVirtualStateInfo(self.cpu, args[0].type, None) vs = VirtualState([info0]) @@ -119,7 +120,7 @@ info1.position = 0 info2 = NotVirtualStateInfo(self.cpu, tp2, info2) info2.position = 0 - return VirtualState([info1]).generalization_of(VirtualState([info2]), cpu=self.cpu) + return VirtualState([info1]).generalization_of(VirtualState([info2]), FakeOptimizer(self.cpu)) assert isgeneral('i', None, 'i', ConstIntBound(7)) assert not isgeneral('i', ConstIntBound(7), 'i', None) @@ -169,24 +170,27 @@ self.check_invalid(info2, info1) self.check_no_guards(info1, info1) self.check_no_guards(info2, info2) + class FieldDescr: + def get_index(self): + return 0 + fielddescr = FieldDescr() fakedescr = object() - fielddescr = object() fldtst(VArrayStateInfo(fakedescr), VArrayStateInfo(fakedescr)) fldtst(VStructStateInfo(fakedescr, [fielddescr]), VStructStateInfo(fakedescr, [fielddescr])) fldtst(VirtualStateInfo(ConstInt(42), [fielddescr]), VirtualStateInfo(ConstInt(42), [fielddescr])) - fldtst(VArrayStructStateInfo(fakedescr, [[fielddescr]]), VArrayStructStateInfo(fakedescr, [[fielddescr]])) + fldtst(VArrayStructStateInfo(fakedescr, [fielddescr], 1), VArrayStructStateInfo(fakedescr, [fielddescr], 1)) def test_known_class_generalization(self): - knownclass1 = info.InstancePtrInfo(ConstPtr(self.myptr)) + knownclass1 = info.InstancePtrInfo(None, ConstPtr(self.myptr)) info1 = NotVirtualStateInfo(self.cpu, 'r', knownclass1) info1.position = 0 - knownclass2 = info.InstancePtrInfo(ConstPtr(self.myptr)) + knownclass2 = info.InstancePtrInfo(None, ConstPtr(self.myptr)) info2 = NotVirtualStateInfo(self.cpu, 'r', knownclass2) info2.position = 0 self.check_no_guards(info1, info2) self.check_no_guards(info2, info1) - knownclass3 = info.InstancePtrInfo(ConstPtr(self.myptr2)) + knownclass3 = info.InstancePtrInfo(None, ConstPtr(self.myptr2)) info3 = NotVirtualStateInfo(self.cpu, 'r', knownclass3) info3.position = 0 self.check_invalid(info1, info3) @@ -207,16 +211,17 @@ # set up infos #unknown_val = PtrOptValue(self.nodebox) #unknownnull_val = PtrOptValue(BoxPtr(self.nullptr)) + opt = FakeOptimizer(self.cpu) unknown_info = NotVirtualStateInfo(self.cpu, 'r', None) nonnull_info = NotVirtualStateInfo(self.cpu, 'r', info.NonNullPtrInfo()) classbox1 = self.cpu.ts.cls_of_box(ConstPtr(self.nodeaddr)) knownclass_info = NotVirtualStateInfo(self.cpu, 'r', - info.InstancePtrInfo(classbox1)) + info.InstancePtrInfo(None, classbox1)) classbox2 = self.cpu.ts.cls_of_box(ConstPtr(self.node2addr)) knownclass2_info = NotVirtualStateInfo(self.cpu, 'r', - info.InstancePtrInfo(classbox2)) + info.InstancePtrInfo(None, classbox2)) constant_info = NotVirtualStateInfo(self.cpu, 'i', ConstIntBound(1)) @@ -241,7 +246,7 @@ # unknown knownclass self.check_no_guards(unknown_info, knownclass_info, - InputArgRef(), info.InstancePtrInfo(classbox1)) + InputArgRef(), info.InstancePtrInfo(None, classbox1)) self.check_no_guards(unknown_info, knownclass_info) # unknown constant @@ -257,10 +262,10 @@ """ nonnullbox = InputArgRef(self.nodeaddr) nonnullbox2 = InputArgRef(self.node2addr) - knownclassopinfo = info.InstancePtrInfo(classbox1) - knownclass2opinfo = info.InstancePtrInfo(classbox2) + knownclassopinfo = info.InstancePtrInfo(None, classbox1) + knownclass2opinfo = info.InstancePtrInfo(None, classbox2) self.guards(nonnull_info, unknown_info, nonnullbox, - None, expected) + nonnullbox, expected) self.check_invalid(nonnull_info, unknown_info, InputArgRef(), None) self.check_invalid(nonnull_info, unknown_info) self.check_invalid(nonnull_info, unknown_info) @@ -271,7 +276,7 @@ # nonnull knownclass self.check_no_guards(nonnull_info, knownclass_info, nonnullbox, - info.InstancePtrInfo(classbox1)) + info.InstancePtrInfo(None, classbox1)) self.check_no_guards(nonnull_info, knownclass_info) # nonnull constant @@ -292,11 +297,11 @@ guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ self.guards(knownclass_info, unknown_info, InputArgRef(self.nodeaddr), - None, expected) + InputArgRef(self.nodeaddr), expected) self.check_invalid(knownclass_info, unknown_info, InputArgRef(), None) self.check_invalid(knownclass_info, unknown_info, InputArgRef(self.node2addr), - info.InstancePtrInfo(classbox2)) + InputArgRef(self.node2addr)) self.check_invalid(knownclass_info, unknown_info) self.check_invalid(knownclass_info, unknown_info) self.check_invalid(knownclass_info, unknown_info) @@ -307,7 +312,7 @@ guard_class(p0, ConstClass(node_vtable)) [] """ self.guards(knownclass_info, nonnull_info, InputArgRef(self.nodeaddr), - None, expected) + InputArgRef(self.nodeaddr), expected) self.check_invalid(knownclass_info, nonnull_info, InputArgRef(self.node2addr), None) self.check_invalid(knownclass_info, nonnull_info) @@ -335,8 +340,8 @@ [i0] guard_value(i0, 1) [] """ - self.guards(constant_info, unknown_info, InputArgInt(1), - ConstIntBound(1), expected) + self.guards(constant_info, unknown_info, InputArgInt(), + InputArgInt(1), expected) self.check_invalid(constant_info, unknown_info, InputArgRef(), None) self.check_invalid(constant_info, unknown_info) self.check_invalid(constant_info, unknown_info) @@ -347,9 +352,9 @@ guard_value(i0, 1) [] """ self.guards(constant_info, nonnull_info, ConstInt(1), - ConstIntBound(1), expected) + ConstInt(1), expected) self.check_invalid(constant_info, nonnull_info, - ConstInt(3), ConstIntBound(3)) + ConstInt(3), ConstInt(3)) self.check_invalid(constant_info, nonnull_info) self.check_invalid(constant_info, nonnull_info) @@ -359,7 +364,7 @@ guard_value(p0, ConstPtr(nodeaddr)) [] """ self.guards(constant_ptr_info, knownclass_info, - const_nonnull, info.ConstPtrInfo(const_nonnull), expected) + const_nonnull, const_nonnull, expected) self.check_invalid(constant_info, knownclass_info, InputArgRef()) self.check_invalid(constant_info, knownclass_info) self.check_invalid(constant_info, knownclass_info) @@ -386,8 +391,8 @@ i2 = int_le(i0, 30) guard_true(i2) [] """ - self.guards(info1, info2, InputArgInt(), value1, expected) - self.check_invalid(info1, info2, InputArgInt(50)) + self.guards(info1, info2, InputArgInt(), InputArgInt(15), expected) + self.check_invalid(info1, info2, InputArgInt(50), InputArgInt(50)) def test_intbounds_constant(self): value1 = IntUnbounded() @@ -402,25 +407,28 @@ def test_known_class(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) - value1 = info.InstancePtrInfo(classbox) + value1 = info.InstancePtrInfo(None, classbox) info1 = NotVirtualStateInfo(self.cpu, 'r', value1) info2 = NotVirtualStateInfo(self.cpu, 'r', None) expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ - self.guards(info1, info2, InputArgRef(self.nodeaddr), None, expected) + self.guards(info1, info2, InputArgRef(), + InputArgRef(self.nodeaddr), expected) self.check_invalid(info1, info2, InputArgRef()) def test_known_class_value(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) - value1 = info.InstancePtrInfo(classbox) + value1 = info.InstancePtrInfo(None, classbox) box = InputArgRef() guards = [] - value1.make_guards(box, guards) + value1.make_guards(box, guards, FakeOptimizer(self.cpu)) expected = """ [p0] - guard_nonnull_class(p0, ConstClass(node_vtable)) [] + guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_class(p0, ConstClass(node_vtable)) [] """ self.compare(guards, expected, [box]) From noreply at buildbot.pypy.org Fri Sep 4 17:25:18 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 17:25:18 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix import error Message-ID: <20150904152518.E4ECF1C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79433:54877cf6df19 Date: 2015-09-04 17:25 +0200 http://bitbucket.org/pypy/pypy/changeset/54877cf6df19/ Log: fix import error diff --git a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py --- a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py @@ -16,7 +16,7 @@ from rpython.jit.metainterp.compile import LoopCompileData from rpython.jit.metainterp.optimizeopt.virtualstate import \ NotVirtualStateInfo, LEVEL_CONSTANT, LEVEL_UNKNOWN, LEVEL_KNOWNCLASS,\ - VirtualStateInfo, BadVirtualState + VirtualStateInfo from rpython.jit.metainterp.optimizeopt import info from rpython.jit.codewriter import heaptracker diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -9,7 +9,7 @@ Optimization, LoopInfo, MININT, MAXINT from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo from rpython.jit.metainterp.optimizeopt.virtualstate import ( - VirtualStateConstructor, VirtualStatesCantMatch, BadVirtualState) + VirtualStateConstructor, VirtualStatesCantMatch) from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp from rpython.jit.metainterp import compile from rpython.rlib.debug import debug_print @@ -149,7 +149,7 @@ self.optimizer, force_boxes=True) for arg in args: self.optimizer.force_box(arg) - except BadVirtualState: + except VirtualStatesCantMatch: raise InvalidLoop extra_same_as = self.short_preamble_producer.extra_same_as[:] target_token = self.finalize_short_preamble(label_op, From noreply at buildbot.pypy.org Fri Sep 4 17:35:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 17:35:13 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: reenable log noopt Message-ID: <20150904153513.5B1521C14C3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79434:61597770d302 Date: 2015-09-04 17:35 +0200 http://bitbucket.org/pypy/pypy/changeset/61597770d302/ Log: reenable log noopt 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 @@ -50,9 +50,10 @@ """Optimize loop.operations to remove internal overheadish operations. """ debug_start("jit-optimize") - #inputargs = start_label.getarglist() + inputargs = compile_data.start_label.getarglist() try: - #logops = metainterp_sd.logger_noopt.log_loop(inputargs, operations) + metainterp_sd.logger_noopt.log_loop(inputargs, + compile_data.operations) optimizations, unroll = build_opt_chain(metainterp_sd, compile_data.enable_opts) return compile_data.optimize(metainterp_sd, jitdriver_sd, From noreply at buildbot.pypy.org Fri Sep 4 17:52:12 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 4 Sep 2015 17:52:12 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: merged optresult-unroll into vecopt-merge Message-ID: <20150904155212.F2D8C1C1414@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79435:9add01daf60f Date: 2015-09-04 17:52 +0200 http://bitbucket.org/pypy/pypy/changeset/9add01daf60f/ Log: merged optresult-unroll into vecopt-merge diff too long, truncating to 2000 out of 45372 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -352,8 +352,7 @@ Except when otherwise stated (look for LICENSE files or copyright/license information at the beginning of each file) the files in the 'lib-python/2.7' directory are all copyrighted by the Python Software Foundation and licensed -under the Python Software License of which you can find a copy here: -http://www.python.org/doc/Copyright.html +under the terms that you can find here: https://docs.python.org/2/license.html License for 'pypy/module/unicodedata/' ====================================== @@ -435,4 +434,4 @@ The code is based on gperftools. You may see a copy of the License for it at - https://code.google.com/p/gperftools/source/browse/COPYING + https://github.com/gperftools/gperftools/blob/master/COPYING diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -308,7 +308,10 @@ if (len(data) != 8 or data[:4] != imp.get_magic() or struct.unpack(" -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include # endif #endif diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -15,9 +15,11 @@ except ImportError: lock = None -_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", - re.MULTILINE) +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") @@ -39,6 +41,7 @@ macros = {} for match in _r_define.finditer(csource): macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) # Replace "[...]" with "[__dotdotdotarray__]" @@ -423,13 +426,10 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - elif (len(params) == 1 and - isinstance(params[0].type, pycparser.c_ast.TypeDecl) and - isinstance(params[0].type.type, pycparser.c_ast.IdentifierType) - and list(params[0].type.type.names) == ['void']): - del params[0] args = [self._as_func_arg(self._get_type(argdeclnode.type)) for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] result = self._get_type(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -4,11 +4,6 @@ VERSION = "0x2601" -try: - int_type = (int, long) -except NameError: # Python 3 - int_type = int - class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -81,10 +81,16 @@ allsources.extend(kwds.pop('sources', [])) ext = Extension(name=module_name, sources=allsources, **kwds) - def make_mod(tmpdir): + def make_mod(tmpdir, pre_run=None): c_file = os.path.join(tmpdir, module_name + source_extension) log.info("generating cffi module %r" % c_file) mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) updated = recompiler.make_c_source(ffi, module_name, source, c_file) if not updated: log.info("already up-to-date") @@ -98,7 +104,8 @@ class build_ext_make_mod(base_class): def run(self): if ext.sources[0] == '$PLACEHOLDER': - ext.sources[0] = make_mod(self.build_temp) + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) base_class.run(self) dist.cmdclass['build_ext'] = build_ext_make_mod # NB. multiple runs here will create multiple 'build_ext_make_mod' diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -28,7 +28,7 @@ def _where_is_errno(): return standard_c_lib.__errno_location() -elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'): +elif sys.platform == 'darwin' or sys.platform.startswith('freebsd'): standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int) standard_c_lib.__error.argtypes = None def _where_is_errno(): diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -46,7 +46,11 @@ source. It'll acquire the GIL. Note: this is meant to be called *only once* or a few times at most. See - the `more complete example`_ below. + the `more complete example`_ below. In PyPy <= 2.6.0, the globals + dictionary is *reused* across multiple calls, giving potentially + strange results (e.g. objects dying too early). In PyPy >= 2.6.1, + you get a new globals dictionary for every call (but then, all globals + dictionaries are all kept alive forever, in ``sys._pypy_execute_source``). .. function:: int pypy_execute_source_ptr(char* source, void* ptr); diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -31,15 +31,14 @@ and add the new file to pypy/doc/index-of-whatsnew.rst * go to pypy/tool/release and run ``force-builds.py `` - The following binaries should be built, however, we need more buildbots - - JIT: windows, linux, os/x, armhf, armel - - no JIT: windows, linux, os/x - - sandbox: linux, os/x + The following JIT binaries should be built, however, we need more buildbots + windows, linux-32, linux-64, osx64, armhf-raring, armhf-raspberrian, armel, + freebsd64 * wait for builds to complete, make sure there are no failures * download the builds, repackage binaries. Tag the release version and download and repackage source from bitbucket. You may find it - convenient to use the ``repackage.sh`` script in pypy/tools to do this. + convenient to use the ``repackage.sh`` script in pypy/tool/release to do this. Otherwise repackage and upload source "-src.tar.bz2" to bitbucket and to cobra, as some packagers prefer a clearly labeled source package diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-2.6.1.rst whatsnew-2.6.0.rst whatsnew-2.5.1.rst whatsnew-2.5.0.rst diff --git a/pypy/doc/whatsnew-2.6.1.rst b/pypy/doc/whatsnew-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-2.6.1.rst @@ -0,0 +1,76 @@ +======================== +What's new in PyPy 2.6.1 +======================== + +.. this is a revision shortly after release-2.6.0 +.. startrev: 91904d5c5188 + +.. branch: use_min_scalar +Correctly resolve the output dtype of ufunc(array, scalar) calls. + +.. branch: stdlib-2.7.10 + +Update stdlib to version 2.7.10 + +.. branch: issue2062 + +.. branch: disable-unroll-for-short-loops +The JIT no longer performs loop unrolling if the loop compiles to too much code. + +.. branch: run-create_cffi_imports + +Build cffi import libraries as part of translation by monkey-patching an +additional task into translation + +.. branch: int-float-list-strategy + +Use a compact strategy for Python lists that mix integers and floats, +at least if the integers fit inside 32 bits. These lists are now +stored as an array of floats, like lists that contain only floats; the +difference is that integers are stored as tagged NaNs. (This should +have no visible effect! After ``lst = [42, 42.5]``, the value of +``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) + +.. branch: cffi-callback-onerror +Part of cffi 1.2. + +.. branch: cffi-new-allocator +Part of cffi 1.2. + +.. branch: unicode-dtype + +Partial implementation of unicode dtype and unicode scalars. + +.. branch: dtypes-compatability + +Improve compatibility with numpy dtypes; handle offsets to create unions, +fix str() and repr(), allow specifying itemsize, metadata and titles, add flags, +allow subclassing dtype + +.. branch: indexing + +Refactor array indexing to support ellipses. + +.. branch: numpy-docstrings + +Allow the docstrings of built-in numpy objects to be set at run-time. + +.. branch: nditer-revisited + +Implement nditer 'buffered' flag and fix some edge cases + +.. branch: ufunc-reduce + +Allow multiple axes in ufunc.reduce() + +.. branch: fix-tinylang-goals + +Update tinylang goals to match current rpython + +.. branch: vmprof-review + +Clean up of vmprof, notably to handle correctly multiple threads + +.. branch: no_boehm_dl + +Remove extra link library from Boehm 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 @@ -2,67 +2,8 @@ What's new in PyPy 2.6+ ======================= -.. this is a revision shortly after release-2.6.0 -.. startrev: 91904d5c5188 - -.. branch: use_min_scalar -Correctly resolve the output dtype of ufunc(array, scalar) calls. - -.. branch: stdlib-2.7.10 - -Update stdlib to version 2.7.10 - -.. branch: issue2062 - -.. branch: disable-unroll-for-short-loops -The JIT no longer performs loop unrolling if the loop compiles to too much code. - -.. branch: run-create_cffi_imports - -Build cffi import libraries as part of translation by monkey-patching an -additional task into translation - -.. branch: int-float-list-strategy - -Use a compact strategy for Python lists that mix integers and floats, -at least if the integers fit inside 32 bits. These lists are now -stored as an array of floats, like lists that contain only floats; the -difference is that integers are stored as tagged NaNs. (This should -have no visible effect! After ``lst = [42, 42.5]``, the value of -``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) - -.. branch: cffi-callback-onerror -.. branch: cffi-new-allocator - -.. branch: unicode-dtype - -Partial implementation of unicode dtype and unicode scalars. - -.. branch: dtypes-compatability - -Improve compatibility with numpy dtypes; handle offsets to create unions, -fix str() and repr(), allow specifying itemsize, metadata and titles, add flags, -allow subclassing dtype - -.. branch: indexing - -Refactor array indexing to support ellipses. - -.. branch: numpy-docstrings - -Allow the docstrings of built-in numpy objects to be set at run-time. - -.. branch: nditer-revisited - -Implement nditer 'buffered' flag and fix some edge cases - -.. branch: ufunc-reduce - -Allow multiple axes in ufunc.reduce() - -.. branch: fix-tinylang-goals - -Update tinylang goals to match current rpython +.. this is a revision shortly after release-2.6.1 +.. startrev: 07769be4057b .. branch: vecopt .. branch: vecopt-merge diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -128,13 +128,7 @@ @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): - after = rffi.aroundstate.after - if after: after() - source = rffi.charp2str(ll_source) - res = _pypy_execute_source(source) - before = rffi.aroundstate.before - if before: before() - return rffi.cast(rffi.INT, res) + return pypy_execute_source_ptr(ll_source, 0) @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_execute_source_ptr') @@ -142,9 +136,7 @@ after = rffi.aroundstate.after if after: after() source = rffi.charp2str(ll_source) - space.setitem(w_globals, space.wrap('c_argument'), - space.wrap(ll_ptr)) - res = _pypy_execute_source(source) + res = _pypy_execute_source(source, ll_ptr) before = rffi.aroundstate.before if before: before() return rffi.cast(rffi.INT, res) @@ -169,15 +161,21 @@ before = rffi.aroundstate.before if before: before() - w_globals = space.newdict() - space.setitem(w_globals, space.wrap('__builtins__'), - space.builtin_modules['__builtin__']) - - def _pypy_execute_source(source): + def _pypy_execute_source(source, c_argument): try: - compiler = space.createcompiler() - stmt = compiler.compile(source, 'c callback', 'exec', 0) - stmt.exec_code(space, w_globals, w_globals) + w_globals = space.newdict(module=True) + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + space.setitem(w_globals, space.wrap('c_argument'), + space.wrap(c_argument)) + space.appexec([space.wrap(source), w_globals], """(src, glob): + import sys + stmt = compile(src, 'c callback', 'exec') + if not hasattr(sys, '_pypy_execute_source'): + sys._pypy_execute_source = [] + sys._pypy_execute_source.append(glob) + exec stmt in glob + """) except OperationError, e: debug("OperationError:") debug(" operror-type: " + e.w_type.getname(space)) @@ -343,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy(pypy_hooks) + #from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy()#pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -62,6 +62,7 @@ } interpleveldefs = { + 'attach_gdb' : 'interp_magic.attach_gdb', 'internal_repr' : 'interp_magic.internal_repr', 'bytebuffer' : 'bytebuffer.bytebuffer', 'identity_dict' : 'interp_identitydict.W_IdentityDict', @@ -100,8 +101,6 @@ def setup_after_space_initialization(self): """NOT_RPYTHON""" - if not self.space.config.translating: - self.extra_interpdef('interp_pdb', 'interp_magic.interp_pdb') if self.space.config.objspace.std.withmethodcachecounter: self.extra_interpdef('method_cache_counter', 'interp_magic.method_cache_counter') @@ -112,18 +111,22 @@ 'interp_magic.mapdict_cache_counter') PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) + # XXX + # the following code prevents --fork-before=pyjitpl from working, + # proper fix would be to use some llop that is only rendered by the + # JIT # - try: - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect() - self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) - except Exception: - if self.space.config.translation.jit: - raise - else: - pass # ok fine to ignore in this case + #try: + # from rpython.jit.backend import detect_cpu + # model = detect_cpu.autodetect() + # self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + #except Exception: + # if self.space.config.translation.jit: + # raise + # else: + # pass # ok fine to ignore in this case # - if self.space.config.translation.jit: - features = detect_cpu.getcpufeatures(model) - self.extra_interpdef('jit_backend_features', - 'space.wrap(%r)' % features) + #if self.space.config.translation.jit: + ## features = detect_cpu.getcpufeatures(model) + # self.extra_interpdef('jit_backend_features', + # 'space.wrap(%r)' % features) diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -15,12 +15,10 @@ return space.wrap('%r' % (w_object,)) -def interp_pdb(space): - """Run an interp-level pdb. - This is not available in translated versions of PyPy.""" - assert not we_are_translated() - import pdb - pdb.set_trace() +def attach_gdb(space): + """Run an interp-level gdb (or pdb when untranslated)""" + from rpython.rlib.debug import attach_gdb + attach_gdb() @unwrap_spec(name=str) diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.2.0" +VERSION = "1.2.1" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -3427,4 +3427,4 @@ def test_version(): # this test is here mostly for PyPy - assert __version__ == "1.2.0" + assert __version__ == "1.2.1" diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -1,8 +1,12 @@ +import sys + class AppTestMemory: spaceconfig = dict(usemodules=('_multiprocessing', 'mmap', '_rawffi', 'itertools', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii')) + if sys.platform != 'win32': + spaceconfig['usemodules'] += ('fcntl',) def test_address_of(self): import _multiprocessing diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py b/pypy/module/_multiprocessing/test/test_semaphore.py --- a/pypy/module/_multiprocessing/test/test_semaphore.py +++ b/pypy/module/_multiprocessing/test/test_semaphore.py @@ -1,12 +1,19 @@ +import sys + from pypy.module._multiprocessing.interp_semaphore import ( RECURSIVE_MUTEX, SEMAPHORE) class AppTestSemaphore: spaceconfig = dict(usemodules=('_multiprocessing', 'thread', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii', 'struct')) + if sys.platform == 'win32': + spaceconfig['usemodules'] += ('_rawffi',) + else: + spaceconfig['usemodules'] += ('fcntl',) + def setup_class(cls): cls.w_SEMAPHORE = cls.space.wrap(SEMAPHORE) cls.w_RECURSIVE = cls.space.wrap(RECURSIVE_MUTEX) diff --git a/pypy/module/_vmprof/__init__.py b/pypy/module/_vmprof/__init__.py --- a/pypy/module/_vmprof/__init__.py +++ b/pypy/module/_vmprof/__init__.py @@ -1,4 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule +from rpython.rlib.rvmprof import VMProfPlatformUnsupported class Module(MixedModule): """ @@ -19,4 +20,7 @@ # already found by the annotator to be the original empty # method, and the annotator doesn't notice that interp_vmprof.py # (loaded later) replaces this method. -import pypy.module._vmprof.interp_vmprof +try: + import pypy.module._vmprof.interp_vmprof +except VMProfPlatformUnsupported, e: + pass diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -21,11 +21,12 @@ i = 0 count = 0 i += 5 * WORD # header - assert s[i] == '\x04' - i += 1 # marker - assert s[i] == '\x04' - i += 1 # length - i += len('pypy') + assert s[i ] == '\x05' # MARKER_HEADER + assert s[i + 1] == '\x00' # 0 + assert s[i + 2] == '\x01' # VERSION_THREAD_ID + assert s[i + 3] == chr(4) # len('pypy') + assert s[i + 4: i + 8] == 'pypy' + i += 8 while i < len(s): if s[i] == '\x03': break diff --git a/pypy/module/_vmprof/test/test_direct.py b/pypy/module/_vmprof/test/test_direct.py --- a/pypy/module/_vmprof/test/test_direct.py +++ b/pypy/module/_vmprof/test/test_direct.py @@ -42,7 +42,7 @@ } -""" + open(str(srcdir.join("rvmprof_get_custom_offset.h"))).read()) +""" + open(str(srcdir.join("vmprof_get_custom_offset.h"))).read()) class TestDirect(object): def test_infrastructure(self): diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -379,6 +379,8 @@ PyObject *ht_name, *ht_slots; } PyHeapTypeObject; +#define PyObject_Bytes PyObject_Str + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -52,11 +52,16 @@ @jit.unroll_safe def setslice(self, space, arr): - if len(arr.get_shape()) > 0 and len(self.get_shape()) == 0: - raise oefmt(space.w_ValueError, - "could not broadcast input array from shape " - "(%s) into shape ()", - ','.join([str(x) for x in arr.get_shape()])) + if len(arr.get_shape()) > len(self.get_shape()): + # record arrays get one extra dimension + if not self.dtype.is_record() or \ + len(arr.get_shape()) > len(self.get_shape()) + 1: + raise oefmt(space.w_ValueError, + "could not broadcast input array from shape " + "(%s) into shape (%s)", + ','.join([str(x) for x in arr.get_shape()]), + ','.join([str(x) for x in self.get_shape()]), + ) shape = shape_agreement(space, self.get_shape(), arr) impl = arr.implementation if impl.storage == self.storage: diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py --- a/pypy/module/micronumpy/descriptor.py +++ b/pypy/module/micronumpy/descriptor.py @@ -588,7 +588,8 @@ return space.newtuple([w_class, builder_args, data]) def descr_setstate(self, space, w_data): - if self.fields is None: # if builtin dtype + if self.fields is None and not isinstance(self.itemtype, types.VoidType): + # if builtin dtype (but not w_voiddtype) return space.w_None version = space.int_w(space.getitem(w_data, space.wrap(0))) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -278,6 +278,47 @@ return target +def split_iter(arr, axis_flags): + """Prepare 2 iterators for nested iteration over `arr`. + + Arguments: + arr: instance of BaseConcreteArray + axis_flags: list of bools, one for each dimension of `arr`.The inner + iterator operates over the dimensions for which the flag is True + """ + shape = arr.get_shape() + strides = arr.get_strides() + backstrides = arr.get_backstrides() + shapelen = len(shape) + assert len(axis_flags) == shapelen + inner_shape = [-1] * shapelen + inner_strides = [-1] * shapelen + inner_backstrides = [-1] * shapelen + outer_shape = [-1] * shapelen + outer_strides = [-1] * shapelen + outer_backstrides = [-1] * shapelen + for i in range(len(shape)): + if axis_flags[i]: + inner_shape[i] = shape[i] + inner_strides[i] = strides[i] + inner_backstrides[i] = backstrides[i] + outer_shape[i] = 1 + outer_strides[i] = 0 + outer_backstrides[i] = 0 + else: + outer_shape[i] = shape[i] + outer_strides[i] = strides[i] + outer_backstrides[i] = backstrides[i] + inner_shape[i] = 1 + inner_strides[i] = 0 + inner_backstrides[i] = 0 + inner_iter = ArrayIter(arr, support.product(inner_shape), + inner_shape, inner_strides, inner_backstrides) + outer_iter = ArrayIter(arr, support.product(outer_shape), + outer_shape, outer_strides, outer_backstrides) + return inner_iter, outer_iter + + reduce_flat_driver = jit.JitDriver( name='numpy_reduce_flat', greens = ['shapelen', 'func', 'done_func', 'calc_dtype'], reds = 'auto', @@ -311,34 +352,8 @@ out_iter, out_state = out.create_iter() out_iter.track_index = False shape = w_arr.get_shape() - strides = w_arr.implementation.get_strides() - backstrides = w_arr.implementation.get_backstrides() shapelen = len(shape) - inner_shape = [-1] * shapelen - inner_strides = [-1] * shapelen - inner_backstrides = [-1] * shapelen - outer_shape = [-1] * shapelen - outer_strides = [-1] * shapelen - outer_backstrides = [-1] * shapelen - for i in range(len(shape)): - if axis_flags[i]: - inner_shape[i] = shape[i] - inner_strides[i] = strides[i] - inner_backstrides[i] = backstrides[i] - outer_shape[i] = 1 - outer_strides[i] = 0 - outer_backstrides[i] = 0 - else: - outer_shape[i] = shape[i] - outer_strides[i] = strides[i] - outer_backstrides[i] = backstrides[i] - inner_shape[i] = 1 - inner_strides[i] = 0 - inner_backstrides[i] = 0 - inner_iter = ArrayIter(w_arr.implementation, support.product(inner_shape), - inner_shape, inner_strides, inner_backstrides) - outer_iter = ArrayIter(w_arr.implementation, support.product(outer_shape), - outer_shape, outer_strides, outer_backstrides) + inner_iter, outer_iter = split_iter(w_arr.implementation, axis_flags) assert outer_iter.size == out_iter.size if identity is not None: @@ -491,17 +506,51 @@ arg_driver = jit.JitDriver(name='numpy_' + op_name, greens = ['shapelen', 'dtype'], reds = 'auto') + arg_flat_driver = jit.JitDriver(name='numpy_flat_' + op_name, + greens = ['shapelen', 'dtype'], + reds = 'auto') - def argmin_argmax(arr): + def argmin_argmax(space, w_arr, w_out, axis): + from pypy.module.micronumpy.descriptor import get_dtype_cache + dtype = w_arr.get_dtype() + shapelen = len(w_arr.get_shape()) + axis_flags = [False] * shapelen + axis_flags[axis] = True + inner_iter, outer_iter = split_iter(w_arr.implementation, axis_flags) + outer_state = outer_iter.reset() + out_iter, out_state = w_out.create_iter() + while not outer_iter.done(outer_state): + inner_state = inner_iter.reset() + inner_state.offset = outer_state.offset + cur_best = inner_iter.getitem(inner_state) + inner_state = inner_iter.next(inner_state) + result = 0 + idx = 1 + while not inner_iter.done(inner_state): + arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) + w_val = inner_iter.getitem(inner_state) + new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) + if dtype.itemtype.ne(new_best, cur_best): + result = idx + cur_best = new_best + inner_state = inner_iter.next(inner_state) + idx += 1 + result = get_dtype_cache(space).w_longdtype.box(result) + out_iter.setitem(out_state, result) + out_state = out_iter.next(out_state) + outer_state = outer_iter.next(outer_state) + return w_out + + def argmin_argmax_flat(w_arr): result = 0 idx = 1 - dtype = arr.get_dtype() - iter, state = arr.create_iter() + dtype = w_arr.get_dtype() + iter, state = w_arr.create_iter() cur_best = iter.getitem(state) state = iter.next(state) - shapelen = len(arr.get_shape()) + shapelen = len(w_arr.get_shape()) while not iter.done(state): - arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) + arg_flat_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) w_val = iter.getitem(state) new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) if dtype.itemtype.ne(new_best, cur_best): @@ -510,9 +559,10 @@ state = iter.next(state) idx += 1 return result - return argmin_argmax -argmin = _new_argmin_argmax('min') -argmax = _new_argmin_argmax('max') + + return argmin_argmax, argmin_argmax_flat +argmin, argmin_flat = _new_argmin_argmax('min') +argmax, argmax_flat = _new_argmin_argmax('max') dot_driver = jit.JitDriver(name = 'numpy_dot', greens = ['dtype'], diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -23,6 +23,8 @@ get_shape_from_iterable, shape_agreement, shape_agreement_multiple, is_c_contiguous, is_f_contiguous, calc_strides, new_view) from pypy.module.micronumpy.casting import can_cast_array +from pypy.module.micronumpy.descriptor import get_dtype_cache + def _match_dot_shapes(space, left, right): @@ -245,6 +247,20 @@ if space.is_w(w_idx, space.w_Ellipsis): self.implementation.setslice(space, convert_to_array(space, w_value)) return + # TODO: multiarray/mapping.c calls a subclass's __getitem__ here, which + # is a big performance hit but necessary for the matrix class. The original + # C code is like: + #/* + #* WARNING: There is a huge special case here. If this is not a + #* base class array, we have to get the view through its + #* very own index machinery. + #* Many subclasses should probably call __setitem__ + #* with a base class ndarray view to avoid this. + #*/ + #else if (!(index_type & (HAS_FANCY | HAS_SCALAR_ARRAY)) + # && !PyArray_CheckExact(self)) { + #view = (PyArrayObject *)PyObject_GetItem((PyObject *)self, ind); + elif isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool() \ and w_idx.ndims() > 0: self.setitem_filter(space, w_idx, convert_to_array(space, w_value)) @@ -484,7 +500,7 @@ return self.implementation.swapaxes(space, self, axis1, axis2) def descr_nonzero(self, space): - index_type = descriptor.get_dtype_cache(space).w_int64dtype + index_type = get_dtype_cache(space).w_int64dtype return self.implementation.nonzero(space, index_type) def descr_tolist(self, space): @@ -812,7 +828,7 @@ if self.get_dtype().is_bool(): # numpy promotes bool.round() to float16. Go figure. w_out = W_NDimArray.from_shape(space, self.get_shape(), - descriptor.get_dtype_cache(space).w_float16dtype) + get_dtype_cache(space).w_float16dtype) else: w_out = None elif not isinstance(w_out, W_NDimArray): @@ -820,7 +836,7 @@ "return arrays must be of ArrayType")) out = descriptor.dtype_agreement(space, [self], self.get_shape(), w_out) if out.get_dtype().is_bool() and self.get_dtype().is_bool(): - calc_dtype = descriptor.get_dtype_cache(space).w_longdtype + calc_dtype = get_dtype_cache(space).w_longdtype else: calc_dtype = out.get_dtype() @@ -839,7 +855,7 @@ raise oefmt(space.w_ValueError, "a must be a 1-d array") v = convert_to_array(space, w_v) ret = W_NDimArray.from_shape( - space, v.get_shape(), descriptor.get_dtype_cache(space).w_longdtype) + space, v.get_shape(), get_dtype_cache(space).w_longdtype) if side == NPY.SEARCHLEFT: binsearch = loop.binsearch_left else: @@ -1152,7 +1168,7 @@ def impl(self, space, w_axis=None, w_dtype=None, w_out=None, keepdims=False): out = out_converter(space, w_out) if bool_result: - w_dtype = descriptor.get_dtype_cache(space).w_booldtype + w_dtype = get_dtype_cache(space).w_booldtype return getattr(ufuncs.get(space), ufunc_name).reduce( space, self, w_axis, keepdims, out, w_dtype) impl.__name__ = name @@ -1185,13 +1201,8 @@ def _reduce_argmax_argmin_impl(raw_name): op_name = "arg%s" % raw_name + op_name_flat = "arg%s_flat" % raw_name def impl(self, space, w_axis=None, w_out=None): - if not space.is_none(w_axis): - raise oefmt(space.w_NotImplementedError, - "axis unsupported for %s", op_name) - if not space.is_none(w_out): - raise oefmt(space.w_NotImplementedError, - "out unsupported for %s", op_name) if self.get_size() == 0: raise oefmt(space.w_ValueError, "Can't call %s on zero-size arrays", op_name) @@ -1201,7 +1212,17 @@ raise oefmt(space.w_NotImplementedError, '%s not implemented for %s', op_name, self.get_dtype().get_name()) - return space.wrap(getattr(loop, op_name)(self)) + shape = self.get_shape() + if space.is_none(w_axis) or len(shape) <= 1: + return space.wrap(getattr(loop, op_name_flat)(self)) + else: + axis = space.int_w(w_axis) + assert axis >= 0 + out_shape = shape[:axis] + shape[axis+1:] + dtype = get_dtype_cache(space).w_longdtype + w_out = W_NDimArray.from_shape(space, out_shape, dtype) + return getattr(loop, op_name)(space, self, w_out, axis) + return func_with_new_name(impl, "reduce_%s_impl" % op_name) descr_argmax = _reduce_argmax_argmin_impl("max") diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -350,8 +350,8 @@ assert np.dtype(xyz).name == 'xyz' # another obscure API, used in numpy record.py # it seems numpy throws away the subclass type and parses the spec - a = np.dtype((xyz, [('x', int), ('y', float)])) - assert repr(a) == "dtype([('x', ' 0.5 + assert (a == [[0, 1], [0, 1], [0, 1]]).all() + + def test_ufunc(self): from numpy import array a = array([[1, 2], [3, 4], [5, 6]]) @@ -2908,14 +2918,14 @@ exc = raises(IndexError, "b[0, 1] = 42") assert str(exc.value) == "unsupported iterator index" assert b.index == 1 - a = array([(False, False, False), - (False, False, False), + a = array([(False, False, False), (False, False, False), - ], + (False, False, False), + ], dtype=[('a', '|b1'), ('b', '|b1'), ('c', '|b1')]) - a.flat = [(True, True, True), - (True, True, True), - (True, True, True)] + a.flat = [(True, True, True), + (True, True, True), + (True, True, True)] assert (a.view(bool) == True).all() def test_flatiter_ops(self): @@ -3807,7 +3817,7 @@ assert (a == [1, 2]).all() def test_pickle(self): - from numpy import dtype, array + from numpy import dtype, array, int32 from cPickle import loads, dumps d = dtype([('x', str), ('y', 'int32')]) @@ -3824,6 +3834,11 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + + a = array([(1, [])], dtype=[('a', int32), ('b', int32, 0)]) + assert a['b'].shape == (1, 0) + b = loads(dumps(a)) + assert b['b'].shape == (1, 0) def test_subarrays(self): from numpy import dtype, array, zeros diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -1166,6 +1166,7 @@ assert (logical_xor([True, False, True, False], [1, 2, 0, 0]) == [False, True, True, False]).all() assert (logical_not([True, False]) == [False, True]).all() + assert logical_and.reduce([1.,1.]) == True def test_logn(self): import math diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -511,15 +511,15 @@ W_Ufunc.__init__(self, name, promote_to_largest, promote_to_float, promote_bools, identity, int_only, allow_bool, allow_complex, complex_to_float) self.func = func - self.bool_result = bool_result if name == 'logical_and': self.done_func = done_if_false elif name == 'logical_or': self.done_func = done_if_true else: self.done_func = None + self.bool_result = bool_result or (self.done_func is not None) self.simple_binary = ( - allow_complex and allow_bool and not bool_result and not int_only + allow_complex and allow_bool and not self.bool_result and not int_only and not complex_to_float and not promote_to_float and not promote_bools) @@ -630,7 +630,7 @@ r_dtype.is_complex())): raise oefmt(space.w_TypeError, "ufunc '%s' not supported for the input types", self.name) - if self.bool_result: + if self.bool_result and not self.done_func: # XXX: should actually pass the arrays dtype = find_result_type(space, [], [l_dtype, r_dtype]) bool_dtype = get_dtype_cache(space).w_booldtype diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,16 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - 'set_compile_hook': 'interp_resop.set_compile_hook', - 'set_optimize_hook': 'interp_resop.set_optimize_hook', - 'set_abort_hook': 'interp_resop.set_abort_hook', - 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - 'enable_debug': 'interp_resop.enable_debug', - 'disable_debug': 'interp_resop.disable_debug', - 'ResOperation': 'interp_resop.WrappedOp', - 'DebugMergePoint': 'interp_resop.DebugMergePoint', - 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - 'Box': 'interp_resop.WrappedBox', + #'set_compile_hook': 'interp_resop.set_compile_hook', + #'set_optimize_hook': 'interp_resop.set_optimize_hook', + #'set_abort_hook': 'interp_resop.set_abort_hook', + #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + #'enable_debug': 'interp_resop.enable_debug', + #'disable_debug': 'interp_resop.disable_debug', + #'ResOperation': 'interp_resop.WrappedOp', + #'DebugMergePoint': 'interp_resop.DebugMergePoint', + #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', + #'Box': 'interp_resop.WrappedBox', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -8,7 +8,7 @@ from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance, hlstr from rpython.rtyper.rclass import OBJECT -from rpython.jit.metainterp.resoperation import rop +#from rpython.jit.metainterp.resoperation import rop from rpython.rlib.nonconst import NonConstant from rpython.rlib import jit_hooks from rpython.rlib.jit import Counters diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -100,43 +100,45 @@ assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - ... - guard_class(p0, #, descr=...) - p4 = getfield_gc_pure(p0, descr=) - i5 = getfield_gc(p2, descr=) + guard_class(p1, #, descr=...) + p4 = getfield_gc_pure(p1, descr=) + i5 = getfield_gc(p0, descr=) p6 = getfield_gc_pure(p4, descr=) p7 = getfield_gc_pure(p6, descr=) guard_class(p7, ConstClass(Float64), descr=...) i9 = getfield_gc_pure(p4, descr=) - f10 = raw_load(i9, i5, descr=) - i11 = getfield_gc_pure(p7, descr=) - guard_true(i11, descr=...) + i10 = getfield_gc_pure(p6, descr=) + i12 = int_eq(i10, 61) + i14 = int_eq(i10, 60) + i15 = int_or(i12, i14) + f16 = raw_load(i9, i5, descr=) + guard_true(i15, descr=...) guard_not_invalidated(descr=...) - i12 = float_ne(f10, 0.0) - guard_true(i12, descr=...) - i15 = getfield_gc_pure(p1, descr=) - i16 = int_is_true(i15) - guard_false(i16, descr=...) - i20 = getfield_gc(p2, descr=) - i21 = getfield_gc_pure(p0, descr=) - guard_true(i21, descr=...) - i23 = int_add(i20, 1) - p24 = getfield_gc_pure(p2, descr=) - i25 = getfield_gc_pure(p0, descr=) - i26 = int_is_true(i25) - guard_true(i26, descr=...) - i27 = getfield_gc_pure(p6, descr=) - guard_value(i27, 8, descr=...) - i28 = int_add(i5, 8) - i29 = getfield_gc_pure(p0, descr=) - i30 = int_ge(i23, i29) - guard_false(i30, descr=...) - p32 = new_with_vtable(#) + i18 = float_ne(f16, 0.000000) + guard_true(i18, descr=...) + guard_nonnull_class(p2, ConstClass(W_BoolBox), descr=...) + i20 = getfield_gc_pure(p2, descr=) + i21 = int_is_true(i20) + guard_false(i21, descr=...) + i22 = getfield_gc(p0, descr=) + i23 = getfield_gc_pure(p1, descr=) + guard_true(i23, descr=...) + i25 = int_add(i22, 1) + p26 = getfield_gc_pure(p0, descr=) + i27 = getfield_gc_pure(p1, descr=) + i28 = int_is_true(i27) + guard_true(i28, descr=...) + i29 = getfield_gc_pure(p6, descr=) + i30 = int_add(i5, i29) + i31 = getfield_gc_pure(p1, descr=) + i32 = int_ge(i25, i31) + guard_false(i32, descr=...) + p34 = new_with_vtable(#) {{{ - setfield_gc(p32, i23, descr=) - setfield_gc(p32, p24, descr=) - setfield_gc(p32, i28, descr=) - setfield_gc(p32, p0, descr=) + setfield_gc(p34, p1, descr=) + setfield_gc(p34, i25, descr=) + setfield_gc(p34, p26, descr=) + setfield_gc(p34, i30, descr=) }}} jump(..., descr=...) """) @@ -152,13 +154,12 @@ assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - ... f31 = raw_load(i9, i29, descr=) guard_not_invalidated(descr=...) + i32 = float_ne(f31, 0.000000) + guard_true(i32, descr=...) i34 = getarrayitem_raw(#, #, descr=) # XXX what are these? guard_value(i34, #, descr=...) # XXX don't appear in - i32 = float_ne(f31, 0.000000) - guard_true(i32, descr=...) i35 = getarrayitem_raw(#, #, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, 8) diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py --- a/pypy/module/struct/formatiterator.py +++ b/pypy/module/struct/formatiterator.py @@ -82,7 +82,13 @@ w_index = space.int(w_obj) # wrapped float -> wrapped int or long if w_index is None: raise StructError("cannot convert argument to integer") - return getattr(space, meth)(w_index) + method = getattr(space, meth) + try: + return method(w_index) + except OperationError as e: + if e.match(self.space, self.space.w_OverflowError): + raise StructError("argument out of range") + raise def accept_bool_arg(self): w_obj = self.accept_obj_arg() diff --git a/pypy/module/struct/test/test_struct.py b/pypy/module/struct/test/test_struct.py --- a/pypy/module/struct/test/test_struct.py +++ b/pypy/module/struct/test/test_struct.py @@ -428,6 +428,9 @@ assert s.unpack(s.pack(42)) == (42,) assert s.unpack_from(memoryview(s.pack(42))) == (42,) + def test_overflow(self): + raises(self.struct.error, self.struct.pack, 'i', 1<<65) + class AppTestStructBuffer(object): spaceconfig = dict(usemodules=['struct', '__pypy__']) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py @@ -160,6 +160,35 @@ assert func.name == 'sin' assert func.BType == ', ), , False>' +def test_remove_line_continuation_comments(): + ffi = FFI(backend=FakeBackend()) + ffi.cdef(""" + double // blah \\ + more comments + x(void); + double // blah\\\\ + y(void); + double // blah\\ \ + etc + z(void); + """) + m = ffi.dlopen(lib_m) + m.x + m.y + m.z + +def test_line_continuation_in_defines(): + ffi = FFI(backend=FakeBackend()) + ffi.cdef(""" + #define ABC\\ + 42 + #define BCD \\ + 43 + """) + m = ffi.dlopen(lib_m) + assert m.ABC == 42 + assert m.BCD == 43 + def test_define_not_supported_for_now(): ffi = FFI(backend=FakeBackend()) e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"') @@ -238,6 +267,13 @@ ffi = FFI() ffi.cdef("typedef _Bool bool; void f(bool);") +def test_void_renamed_as_only_arg(): + ffi = FFI() + ffi.cdef("typedef void void_t1;" + "typedef void_t1 void_t;" + "typedef int (*func_t)(void_t);") + assert ffi.typeof("func_t").args == () + def test_win_common_types(): from cffi.commontypes import COMMON_TYPES, _CACHE from cffi.commontypes import win_common_types, resolve_common_type diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -25,6 +25,9 @@ if 1: # test the .cpp mode too kwds.setdefault('source_extension', '.cpp') source = 'extern "C" {\n%s\n}' % (source,) + else: + kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) + + ['-Werror']) return recompiler._verify(ffi, module_name, source, *args, **kwds) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py @@ -318,15 +318,32 @@ import cffi ffi = cffi.FFI() ffi.set_source("pack3.mymod", "/*code would be here*/") + ffi._hi_there = 42 """) with open("setup.py", "w") as f: - f.write("""if 1: + f.write("from __future__ import print_function\n" + """if 1: from setuptools import setup + from distutils.command.build_ext import build_ext + import os + + class TestBuildExt(build_ext): + def pre_run(self, ext, ffi): + print('_make_setuptools_api: in pre_run:', end=" ") + assert ffi._hi_there == 42 + assert ext.name == "pack3.mymod" + fn = os.path.join(os.path.dirname(self.build_lib), + '..', 'see_me') + print('creating %r' % (fn,)) + open(fn, 'w').close() + setup(name='example1', version='0.1', packages=['pack3'], package_dir={'': 'src1'}, - cffi_modules=["src1/pack3/_build.py:ffi"]) + cffi_modules=["src1/pack3/_build.py:ffi"], + cmdclass={'build_ext': TestBuildExt}, + ) """) @chdir_to_tmp @@ -335,6 +352,7 @@ self.run(["setup.py", "build"]) self.check_produced_files({'setup.py': None, 'build': '?', + 'see_me': None, 'src1': {'pack3': {'__init__.py': None, '_build.py': None}}}) @@ -344,6 +362,7 @@ self.run(["setup.py", "build_ext", "-i"]) self.check_produced_files({'setup.py': None, 'build': '?', + 'see_me': None, 'src1': {'pack3': {'__init__.py': None, '_build.py': None, 'mymod.SO': None}}}) diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -116,9 +116,6 @@ class AppTestLockSignals(GenericTestThread): pytestmark = py.test.mark.skipif("os.name != 'posix'") - def setup_class(cls): - cls.w_using_pthread_cond = cls.space.wrap(sys.platform == 'freebsd6') - def w_acquire_retries_on_intr(self, lock): import thread, os, signal, time self.sig_recvd = False @@ -157,8 +154,6 @@ raise KeyboardInterrupt def test_lock_acquire_interruption(self): - if self.using_pthread_cond: - skip('POSIX condition variables cannot be interrupted') import thread, signal, time # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck # in a deadlock. diff --git a/pypy/objspace/std/boolobject.py b/pypy/objspace/std/boolobject.py --- a/pypy/objspace/std/boolobject.py +++ b/pypy/objspace/std/boolobject.py @@ -13,7 +13,7 @@ class W_BoolObject(W_IntObject): def __init__(self, boolval): - self.intval = not not boolval + self.intval = int(not not boolval) def __nonzero__(self): raise Exception("you cannot do that, you must use space.is_true()") diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py --- a/pypy/objspace/std/intobject.py +++ b/pypy/objspace/std/intobject.py @@ -309,17 +309,17 @@ def __init__(self, intval): assert is_valid_int(intval) - self.intval = intval + self.intval = int(intval) def __repr__(self): """representation for debugging purposes""" return "%s(%d)" % (self.__class__.__name__, self.intval) def int_w(self, space, allow_conversion=True): - return int(self.intval) + return self.intval def _int_w(self, space): - return int(self.intval) + return self.intval unwrap = _int_w diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -539,17 +539,19 @@ rangen = unroll.unrolling_iterable(range(n)) nmin1 = n - 1 rangenmin1 = unroll.unrolling_iterable(range(nmin1)) + valnmin1 = "_value%s" % nmin1 class subcls(BaseMapdictObject, supercls): def _init_empty(self, map): - for i in rangen: - setattr(self, "_value%s" % i, erase_item(None)) + for i in rangenmin1: + setattr(self, "_value%s" % i, None) + setattr(self, valnmin1, erase_item(None)) self.map = map def _has_storage_list(self): return self.map.length() > n def _mapdict_get_storage_list(self): - erased = getattr(self, "_value%s" % nmin1) + erased = getattr(self, valnmin1) return unerase_list(erased) def _mapdict_read_storage(self, storageindex): @@ -557,23 +559,21 @@ if storageindex < nmin1: for i in rangenmin1: if storageindex == i: - erased = getattr(self, "_value%s" % i) - return unerase_item(erased) + return getattr(self, "_value%s" % i) if self._has_storage_list(): return self._mapdict_get_storage_list()[storageindex - nmin1] erased = getattr(self, "_value%s" % nmin1) return unerase_item(erased) def _mapdict_write_storage(self, storageindex, value): - erased = erase_item(value) for i in rangenmin1: if storageindex == i: - setattr(self, "_value%s" % i, erased) + setattr(self, "_value%s" % i, value) return if self._has_storage_list(): self._mapdict_get_storage_list()[storageindex - nmin1] = value return - setattr(self, "_value%s" % nmin1, erased) + setattr(self, "_value%s" % nmin1, erase_item(value)) def _mapdict_storage_length(self): if self._has_storage_list(): @@ -585,9 +585,9 @@ len_storage = len(storage) for i in rangenmin1: if i < len_storage: - erased = erase_item(storage[i]) + erased = storage[i] else: - erased = erase_item(None) + erased = None setattr(self, "_value%s" % i, erased) has_storage_list = self._has_storage_list() if len_storage < n: diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -195,7 +195,8 @@ splitted = split(value, self._chr('\t')) try: - ovfcheck(len(splitted) * tabsize) + if tabsize > 0: + ovfcheck(len(splitted) * tabsize) except OverflowError: raise oefmt(space.w_OverflowError, "new string is too long") expanded = oldtoken = splitted.pop(0) @@ -210,6 +211,8 @@ def _tabindent(self, token, tabsize): """calculates distance behind the token to the next tabstop""" + if tabsize <= 0: + return 0 distance = tabsize if token: distance = 0 diff --git a/pypy/objspace/std/test/test_boolobject.py b/pypy/objspace/std/test/test_boolobject.py --- a/pypy/objspace/std/test/test_boolobject.py +++ b/pypy/objspace/std/test/test_boolobject.py @@ -4,6 +4,10 @@ self.false = self.space.w_False self.wrap = self.space.wrap + def test_init(self): + assert (self.false.intval, type(self.false.intval)) == (0, int) + assert (self.true.intval, type(self.true.intval)) == (1, int) + def test_repr(self): assert self.space.eq_w(self.space.repr(self.true), self.wrap("True")) assert self.space.eq_w(self.space.repr(self.false), self.wrap("False")) diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py --- a/pypy/objspace/std/test/test_bytesobject.py +++ b/pypy/objspace/std/test/test_bytesobject.py @@ -388,6 +388,10 @@ skip("Wrong platform") raises((MemoryError, OverflowError), 't\tt\t'.expandtabs, sys.maxint) + def test_expandtabs_0(self): + assert 'x\ty'.expandtabs(0) == 'xy' + assert 'x\ty'.expandtabs(-42) == 'xy' + def test_splitlines(self): s = "" assert s.splitlines() == [] diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py --- a/pypy/objspace/std/test/test_intobject.py +++ b/pypy/objspace/std/test/test_intobject.py @@ -592,6 +592,12 @@ assert ns['a'] == 9007199254740991.0 assert ns['b'] == 9007199254740991.0 + def test_int_of_bool(self): + x = int(False) + assert x == 0 + assert type(x) is int + assert str(x) == "0" + class AppTestIntShortcut(AppTestInt): spaceconfig = {"objspace.std.intshortcut": True} diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -451,12 +451,12 @@ obj = objectcls() obj.user_setup(space, cls) obj.setdictvalue(space, "a", w1) - assert unerase_item(obj._value0) is w1 + assert obj._value0 is w1 assert obj.getdictvalue(space, "a") is w1 assert obj.getdictvalue(space, "b") is None assert obj.getdictvalue(space, "c") is None obj.setdictvalue(space, "a", w2) - assert unerase_item(obj._value0) is w2 + assert obj._value0 is w2 assert obj.getdictvalue(space, "a") == w2 assert obj.getdictvalue(space, "b") is None assert obj.getdictvalue(space, "c") is None @@ -474,7 +474,7 @@ res = obj.deldictvalue(space, "a") assert res - assert unerase_item(obj._value0) is w4 + assert obj._value0 is w4 assert obj.getdictvalue(space, "a") is None assert obj.getdictvalue(space, "b") is w4 assert obj.getdictvalue(space, "c") is None diff --git a/pypy/objspace/std/test/test_unicodeobject.py b/pypy/objspace/std/test/test_unicodeobject.py --- a/pypy/objspace/std/test/test_unicodeobject.py +++ b/pypy/objspace/std/test/test_unicodeobject.py @@ -494,6 +494,10 @@ skip("Wrong platform") raises((OverflowError, MemoryError), u't\tt\t'.expandtabs, sys.maxint) + def test_expandtabs_0(self): + assert u'x\ty'.expandtabs(0) == u'xy' + assert u'x\ty'.expandtabs(-42) == u'xy' + def test_translate(self): assert u'bbbc' == u'abababc'.translate({ord('a'):None}) assert u'iiic' == u'abababc'.translate({ord('a'):None, ord('b'):ord('i')}) diff --git a/pypy/tool/pypyjit.py b/pypy/tool/pypyjit.py --- a/pypy/tool/pypyjit.py +++ b/pypy/tool/pypyjit.py @@ -14,6 +14,9 @@ print >> sys.stderr, __doc__ sys.exit(2) +import sys +sys.setrecursionlimit(100000000) + from pypy.objspace.std import Space from rpython.config.translationoption import set_opt_level from pypy.config.pypyoption import get_pypy_config, set_pypy_opt_level @@ -22,6 +25,7 @@ from rpython.rtyper.lltypesystem import lltype from pypy.interpreter.pycode import PyCode from rpython.translator.goal import unixcheckpoint +import pypy.module.pypyjit.interp_jit config = get_pypy_config(translating=True) config.translation.backendopt.inline_threshold = 0.1 @@ -33,6 +37,8 @@ config.objspace.usemodules.pypyjit = True config.objspace.usemodules.array = False config.objspace.usemodules._weakref = False +config.objspace.usemodules.struct = True +config.objspace.usemodules.time = True config.objspace.usemodules._sre = False config.objspace.usemodules._lsprof = False # @@ -73,6 +79,7 @@ read_code_ptr = llhelper(FPTR, read_code) def entry_point(): + space.startup() from pypy.module.marshal.interp_marshal import loads code = loads(space, space.wrap(hlstr(read_code_ptr()))) assert isinstance(code, PyCode) diff --git a/pypy/tool/pypyjit_demo.py b/pypy/tool/pypyjit_demo.py --- a/pypy/tool/pypyjit_demo.py +++ b/pypy/tool/pypyjit_demo.py @@ -1,8 +1,31 @@ -def f(): - i = 0 - while i < 1303: - i += 1 - return i +import time +l = [] -f() +for i in range(100): + print i + t0 = time.time() + exec """ +def k(a, b, c): + pass + +def g(a, b, c): + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + +def f(i): + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) +for i in range(1000): + f(i) +""" + l.append(time.time() - t0) + +print l diff --git a/pypy/tool/release/force-builds.py b/pypy/tool/release/force-builds.py --- a/pypy/tool/release/force-builds.py +++ b/pypy/tool/release/force-builds.py @@ -28,6 +28,7 @@ # 'pypy-c-app-level-win-x86-32', 'pypy-c-jit-linux-x86-32', 'pypy-c-jit-linux-x86-64', + 'pypy-c-jit-freebsd-9-x86-64', 'pypy-c-jit-macosx-x86-64', 'pypy-c-jit-win-x86-32', 'build-pypy-c-jit-linux-armhf-raring', @@ -42,7 +43,7 @@ import pwd return pwd.getpwuid(os.getuid())[0] -def main(branch, server): +def main(branch, server, user): #XXX: handle release tags #XXX: handle validity checks lock = defer.DeferredLock() @@ -56,7 +57,7 @@ print 'Forcing', builder, '...' url = "http://" + server + "/builders/" + builder + "/force" args = [ - ('username', get_user()), + ('username', user), ('revision', ''), ('forcescheduler', 'Force Scheduler'), ('submit', 'Force Build'), @@ -78,7 +79,8 @@ parser = optparse.OptionParser() parser.add_option("-b", "--branch", help="branch to build", default='') parser.add_option("-s", "--server", help="buildbot server", default="buildbot.pypy.org") + parser.add_option("-u", "--user", help="user name to report", default=get_user()) (options, args) = parser.parse_args() if not options.branch: parser.error("branch option required") - main(options.branch, options.server) + main(options.branch, options.server, user=options.user) diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh --- a/pypy/tool/release/repackage.sh +++ b/pypy/tool/release/repackage.sh @@ -1,12 +1,12 @@ # Edit these appropriately before running this script maj=2 min=6 -rev=0 +rev=1 # This script will download latest builds from the buildmaster, rename the top # level directory, and repackage ready to be uploaded to bitbucket. It will also # download source, assuming a tag for the release already exists, and repackage them. -for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 +for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 freebsd64 do wget http://buildbot.pypy.org/nightly/release-$maj.$min.x/pypy-c-jit-latest-$plat.tar.bz2 tar -xf pypy-c-jit-latest-$plat.tar.bz2 diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -425,8 +425,9 @@ class __extend__(pairtype(SomeString, SomeObject), pairtype(SomeUnicodeString, SomeObject)): - def mod((s_string, args)): - return s_string.__class__() + def mod((s_string, s_arg)): + assert not isinstance(s_arg, SomeTuple) + return pair(s_string, SomeTuple([s_arg])).mod() class __extend__(pairtype(SomeFloat, SomeFloat)): diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -2124,6 +2124,16 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_no_nul_mod(self): + def f(x): + s = "%d" % x + return s + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeString) + assert s.no_nul + + def test_mul_str0(self): def f(s): return s*10 diff --git a/rpython/config/support.py b/rpython/config/support.py --- a/rpython/config/support.py +++ b/rpython/config/support.py @@ -8,7 +8,9 @@ if os.environ.get('MAKEFLAGS'): return 1 # don't override MAKEFLAGS. This will call 'make' without any '-j' option if sys.platform == 'darwin': - return darwin_get_cpu_count() + return sysctl_get_cpu_count('/usr/sbin/sysctl') + elif sys.platform.startswith('freebsd'): + return sysctl_get_cpu_count('/sbin/sysctl') elif not sys.platform.startswith('linux'): return 1 # implement me try: @@ -26,11 +28,10 @@ except: return 1 # we really don't want to explode here, at worst we have 1 -def darwin_get_cpu_count(cmd = "/usr/sbin/sysctl hw.ncpu"): +def sysctl_get_cpu_count(cmd, name='hw.ncpu'): try: - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) - # 'hw.ncpu: 20' - count = proc.communicate()[0].rstrip()[8:] + proc = subprocess.Popen([cmd, '-n', name], stdout=subprocess.PIPE) + count = proc.communicate()[0] return int(count) except (OSError, ValueError): return 1 diff --git a/rpython/config/test/test_support.py b/rpython/config/test/test_support.py --- a/rpython/config/test/test_support.py +++ b/rpython/config/test/test_support.py @@ -52,25 +52,30 @@ finally: os.environ = saved -def test_cpuinfo_darwin(): - if sys.platform != 'darwin': - py.test.skip('mac only') - saved_func = support.darwin_get_cpu_count +def test_cpuinfo_sysctl(): + if sys.platform != 'darwin' and not sys.platform.startswith('freebsd'): + py.test.skip('mac and bsd only') + saved_func = support.sysctl_get_cpu_count saved = os.environ - def count(): + def count(cmd): + if sys.platform == 'darwin': + assert cmd == '/usr/sbin/sysctl' + else: + assert cmd == '/sbin/sysctl' return 42 try: - support.darwin_get_cpu_count = count + support.sysctl_get_cpu_count = count os.environ = FakeEnviron(None) assert support.detect_number_of_processors() == 42 os.environ = FakeEnviron('-j2') assert support.detect_number_of_processors() == 1 finally: os.environ = saved - support.darwin_get_cpu_count = saved_func + support.sysctl_get_cpu_count = saved_func -def test_darwin_get_cpu_count(): - if sys.platform != 'darwin': - py.test.skip('mac only') - assert support.darwin_get_cpu_count() > 0 # hopefully - assert support.darwin_get_cpu_count("false") == 1 +def test_sysctl_get_cpu_count(): + if sys.platform != 'darwin' and not sys.platform.startswith('freebsd'): + py.test.skip('mac and bsd only') + cmd = '/usr/sbin/sysctl' if sys.platform != 'darwin' else '/sbin/sysctl' + assert support.sysctl_get_cpu_count(cmd) > 0 # hopefully + assert support.sysctl_get_cpu_count(cmd, "false") == 1 diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -13,6 +13,11 @@ def _assert_rpythonic(func): """Raise ValueError if ``func`` is obviously not RPython""" + try: + func.func_code.co_cellvars + except AttributeError: + raise ValueError("%r is not RPython: it is likely an unexpected " + "built-in function or type" % (func,)) if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'): raise ValueError("%r is tagged as NOT_RPYTHON" % (func,)) if func.func_code.co_cellvars: diff --git a/rpython/flowspace/test/test_objspace.py b/rpython/flowspace/test/test_objspace.py --- a/rpython/flowspace/test/test_objspace.py +++ b/rpython/flowspace/test/test_objspace.py @@ -1363,6 +1363,15 @@ simplify_graph(graph) assert self.all_operations(graph) == {'bool': 1, 'inplace_add': 1} + def test_unexpected_builtin_function(self): + import itertools + e = py.test.raises(ValueError, build_flow, itertools.permutations) + assert ' is not RPython:' in str(e.value) + e = py.test.raises(ValueError, build_flow, itertools.tee) + assert ' is not RPython:' in str(e.value) + e = py.test.raises(ValueError, build_flow, Exception.__init__) + assert ' is not RPython:' in str(e.value) + DATA = {'x': 5, 'y': 6} diff --git a/rpython/jit/backend/arm/runner.py b/rpython/jit/backend/arm/runner.py --- a/rpython/jit/backend/arm/runner.py +++ b/rpython/jit/backend/arm/runner.py @@ -64,12 +64,6 @@ operations, original_loop_token, log=log) - def clear_latest_values(self, count): - setitem = self.assembler.fail_boxes_ptr.setitem - null = lltype.nullptr(llmemory.GCREF.TO) - for index in range(count): - setitem(index, null) - def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU_ARM.cast_adr_to_int(adr) diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -64,6 +64,7 @@ 'AMD64': MODEL_X86, # win64 'armv7l': MODEL_ARM, 'armv6l': MODEL_ARM, + 'arm': MODEL_ARM, # freebsd }.get(mach) if result is None: 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 @@ -153,15 +153,15 @@ rffi.cast(TYPE, -1) == -1) class ArrayDescr(AbstractDescr): - def __init__(self, A): + all_interiorfielddescrs = None + + def __init__(self, A, runner): self.A = self.OUTERA = A + self._is_pure = A._immutable_field(None) self.concrete_type = '\x00' if isinstance(A, lltype.Struct): self.A = A._flds[A._arrayfld] - def __repr__(self): - return 'ArrayDescr(%r)' % (self.OUTERA,) - def is_array_of_primitives(self): kind = getkind(self.A.OF) return kind == 'float' or \ @@ -169,13 +169,24 @@ kind == '' + def is_always_pure(self): + return self._is_pure + + def get_all_fielddescrs(self): + return self.all_interiorfielddescrs + + def __repr__(self): + return 'ArrayDescr(%r)' % (self.OUTERA,) + + def get_all_fielddescrs(self): + return self.all_interiorfielddescrs + + def __repr__(self): + return 'ArrayDescr(%r)' % (self.OUTERA,) + def is_array_of_pointers(self): return getkind(self.A.OF) == 'ref' - def getflag(self): - from rpython.jit.backend.llsupport.descr import get_type_flag - return get_type_flag(self.A.OF) - def is_array_of_floats(self): return getkind(self.A.OF) == 'float' @@ -206,12 +217,27 @@ return intbounds.get_integer_max( not _is_signed_kind(self.A.OF), rffi.sizeof(self.A.OF)) + def get_type_id(self): + assert isinstance(self.A, lltype.GcArray) + return TypeIDSymbolic(self.A) # integer-like symbolic + class InteriorFieldDescr(AbstractDescr): - def __init__(self, A, fieldname): + def __init__(self, A, fieldname, runner): self.A = A self.fieldname = fieldname self.FIELD = getattr(A.OF, fieldname) + self.arraydescr = runner.arraydescrof(A) + self.fielddescr = runner.fielddescrof(A.OF, fieldname) + + def get_index(self): + return self.fielddescr.get_index() + From noreply at buildbot.pypy.org Fri Sep 4 18:16:33 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 18:16:33 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: Fixing the ARM backend, in-progress Message-ID: <20150904161633.4013A1C14C3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79436:995518da4059 Date: 2015-09-04 17:51 +0200 http://bitbucket.org/pypy/pypy/changeset/995518da4059/ Log: Fixing the ARM backend, in-progress diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -12,8 +12,7 @@ from rpython.jit.backend.arm.opassembler import ResOpAssembler from rpython.jit.backend.arm.regalloc import (Regalloc, CoreRegisterManager, check_imm_arg, VFPRegisterManager, - operations as regalloc_operations, - operations_with_guard as regalloc_operations_with_guard) + operations as regalloc_operations) from rpython.jit.backend.llsupport import jitframe, rewrite from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER, debug_bridge, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale, valid_addressing_size @@ -645,8 +644,10 @@ size_excluding_failure_stuff - loop_head) def _assemble(self, regalloc, inputargs, operations): + self.guard_success_cc = c.cond_none regalloc.compute_hint_frame_locations(operations) self._walk_operations(inputargs, operations, regalloc) + assert self.guard_success_cc == c.cond_none frame_depth = regalloc.get_final_frame_depth() jump_target_descr = regalloc.jump_target_descr if jump_target_descr is not None: @@ -927,6 +928,7 @@ def _walk_operations(self, inputargs, operations, regalloc): fcond = c.AL self._regalloc = regalloc + regalloc.operations = operations while regalloc.position() < len(operations) - 1: regalloc.next_instruction() i = regalloc.position() @@ -935,18 +937,7 @@ opnum = op.getopnum() if op.has_no_side_effect() and op.result not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif self._regalloc.can_merge_with_next_guard(op, i, operations): - guard = operations[i + 1] - assert guard.is_guard() - arglocs = regalloc_operations_with_guard[opnum](regalloc, op, - guard, fcond) - fcond = asm_operations_with_guard[opnum](self, op, - guard, arglocs, regalloc, fcond) - assert fcond is not None - regalloc.next_instruction() - regalloc.possibly_free_vars_for_op(guard) - regalloc.possibly_free_vars(guard.getfailargs()) - elif not we_are_translated() and op.getopnum() == -124: + if not we_are_translated() and op.getopnum() == -124: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) @@ -962,6 +953,7 @@ regalloc.free_temp_vars() regalloc._check_invariants() self.mc.mark_op(None) # end of the loop + regalloc.operations = None def regalloc_emit_extra(self, op, arglocs, fcond, regalloc): # for calls to a function with a specifically-supported OS_xxx @@ -1516,21 +1508,11 @@ raise NotImplementedError(op) -def notimplemented_op_with_guard(self, op, guard_op, arglocs, regalloc, fcond): - print "[ARM/asm] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - asm_operations = [notimplemented_op] * (rop._LAST + 1) -asm_operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) asm_extra_operations = {} for name, value in ResOpAssembler.__dict__.iteritems(): - if name.startswith('emit_guard_'): - opname = name[len('emit_guard_'):] - num = getattr(rop, opname.upper()) - asm_operations_with_guard[num] = value - elif name.startswith('emit_opx_'): + if name.startswith('emit_opx_'): opname = name[len('emit_opx_'):] num = getattr(EffectInfo, 'OS_' + opname.upper()) asm_extra_operations[num] = value diff --git a/rpython/jit/backend/arm/conditions.py b/rpython/jit/backend/arm/conditions.py --- a/rpython/jit/backend/arm/conditions.py +++ b/rpython/jit/backend/arm/conditions.py @@ -13,6 +13,7 @@ GT = 0xC LE = 0xD AL = 0xE +cond_none = -1 opposites = [NE, EQ, CC, CS, PL, MI, VC, VS, LS, HI, LT, GE, LE, GT, AL] diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -6,33 +6,32 @@ from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop + +def flush_cc(asm, condition, result_loc): + # After emitting an instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to 'fp' by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert asm.guard_success_cc == c.cond_none + if result_loc is r.fp: + asm.guard_success_cc = condition + else: + asm.mc.MOV_ri(result_loc.value, 1, condition) + asm.mc.MOV_ri(result_loc.value, 0, c.get_opposite_of(condition)) + + def gen_emit_op_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None reg, res = arglocs self.mc.CMP_ri(reg.value, 0) - self.mc.MOV_ri(res.value, 1, true_cond) - self.mc.MOV_ri(res.value, 0, false_cond) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_guard_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert fcond is not None - assert guard is not None - reg = arglocs[0] - self.mc.CMP_ri(reg.value, 0) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[1:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_op_ri(name, opname): ri_op = getattr(InstrBuilder, '%s_ri' % opname) rr_op = getattr(InstrBuilder, '%s_rr' % opname) @@ -61,8 +60,7 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op(name, condition): - inv = c.get_opposite_of(condition) +def gen_emit_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs @@ -70,32 +68,11 @@ self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) else: self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=condition) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - l0 = arglocs[0] - l1 = arglocs[1] - assert l0.is_core_reg() - - if l1.is_imm(): - self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) - else: - self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - guard_opnum = guard.getopnum() - cond = true_cond - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): @@ -113,34 +90,16 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op(name, cond): - inv = c.get_opposite_of(cond) +def gen_emit_float_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): arg1, arg2, res = arglocs self.mc.VCMP(arg1.value, arg2.value) self.mc.VMRS(cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=cond) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - arg1 = arglocs[0] - arg2 = arglocs[1] - self.mc.VCMP(arg1.value, arg2.value) - self.mc.VMRS(cond=fcond) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - class saved_registers(object): def __init__(self, cb, regs_to_save, vfp_regs_to_save=None): diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -50,42 +50,28 @@ f.__name__ = name return f -def prepare_float_op(name=None, base=True, float_result=True, guard=False): - if guard: - def f(self, op, guard_op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - else: - args = self._prepare_guard(guard_op, locs) - return args - else: - def f(self, op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - if name: - f.__name__ = name - return f +def prepare_unary_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, res] + +def prepare_two_regs_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, loc2, res] + +def prepare_float_cmp(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [loc1, loc2, res] def prepare_op_by_helper_call(name): def f(self, op, fcond): @@ -106,43 +92,28 @@ f.__name__ = name return f -def prepare_cmp_op(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - boxes = list(op.getarglist()) - arg0, arg1 = boxes - imm_a1 = check_imm_box(arg1) +def prepare_int_cmp(self, op, fcond): + assert fcond is not None + boxes = list(op.getarglist()) + arg0, arg1 = boxes + imm_a1 = check_imm_box(arg1) - l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) - if imm_a1: - l1 = self.convert_to_imm(arg1) - else: - l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) + l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) + if imm_a1: + l1 = self.convert_to_imm(arg1) + else: + l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - args = self._prepare_guard(guard_op, [l0, l1]) - return args - if name: - f.__name__ = name - return f + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] -def prepare_op_unary_cmp(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - a0 = op.getarg(0) - assert isinstance(a0, Box) - reg = self.make_sure_var_in_reg(a0) - self.possibly_free_vars_for_op(op) - if guard_op is None: - res = self.force_allocate_reg(op.result, [a0]) - return [reg, res] - else: - return self._prepare_guard(guard_op, [reg]) - if name: - f.__name__ = name - return f +def prepare_unary_cmp(self, op, fcond): + assert fcond is not None + a0 = op.getarg(0) + assert isinstance(a0, Box) + reg = self.make_sure_var_in_reg(a0) + self.possibly_free_vars_for_op(op) + res = self.force_allocate_reg_or_cc(op.result) + return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -5,13 +5,10 @@ from rpython.jit.backend.arm.arch import WORD, DOUBLE_WORD, JITFRAME_FIXED_SIZE from rpython.jit.backend.arm.helper.assembler import (gen_emit_op_by_helper_call, gen_emit_op_unary_cmp, - gen_emit_guard_unary_cmp, gen_emit_op_ri, gen_emit_cmp_op, - gen_emit_cmp_op_guard, gen_emit_float_op, gen_emit_float_cmp_op, - gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg @@ -160,27 +157,13 @@ emit_op_int_gt = gen_emit_cmp_op('int_gt', c.GT) emit_op_int_ge = gen_emit_cmp_op('int_ge', c.GE) - emit_guard_int_lt = gen_emit_cmp_op_guard('int_lt', c.LT) - emit_guard_int_le = gen_emit_cmp_op_guard('int_le', c.LE) - emit_guard_int_eq = gen_emit_cmp_op_guard('int_eq', c.EQ) - emit_guard_int_ne = gen_emit_cmp_op_guard('int_ne', c.NE) - emit_guard_int_gt = gen_emit_cmp_op_guard('int_gt', c.GT) - emit_guard_int_ge = gen_emit_cmp_op_guard('int_ge', c.GE) - emit_op_uint_le = gen_emit_cmp_op('uint_le', c.LS) emit_op_uint_gt = gen_emit_cmp_op('uint_gt', c.HI) emit_op_uint_lt = gen_emit_cmp_op('uint_lt', c.LO) emit_op_uint_ge = gen_emit_cmp_op('uint_ge', c.HS) - emit_guard_uint_le = gen_emit_cmp_op_guard('uint_le', c.LS) - emit_guard_uint_gt = gen_emit_cmp_op_guard('uint_gt', c.HI) - emit_guard_uint_lt = gen_emit_cmp_op_guard('uint_lt', c.LO) - emit_guard_uint_ge = gen_emit_cmp_op_guard('uint_ge', c.HS) - emit_op_ptr_eq = emit_op_instance_ptr_eq = emit_op_int_eq emit_op_ptr_ne = emit_op_instance_ptr_ne = emit_op_int_ne - emit_guard_ptr_eq = emit_guard_instance_ptr_eq = emit_guard_int_eq - emit_guard_ptr_ne = emit_guard_instance_ptr_ne = emit_guard_int_ne emit_op_int_add_ovf = emit_op_int_add emit_op_int_sub_ovf = emit_op_int_sub @@ -188,9 +171,6 @@ emit_op_int_is_true = gen_emit_op_unary_cmp('int_is_true', c.NE) emit_op_int_is_zero = gen_emit_op_unary_cmp('int_is_zero', c.EQ) - emit_guard_int_is_true = gen_emit_guard_unary_cmp('int_is_true', c.NE) - emit_guard_int_is_zero = gen_emit_guard_unary_cmp('int_is_zero', c.EQ) - def emit_op_int_invert(self, op, arglocs, regalloc, fcond): reg, res = arglocs @@ -1125,13 +1105,6 @@ emit_op_float_gt = gen_emit_float_cmp_op('float_gt', c.GT) emit_op_float_ge = gen_emit_float_cmp_op('float_ge', c.GE) - emit_guard_float_lt = gen_emit_float_cmp_op_guard('float_lt', c.VFP_LT) - emit_guard_float_le = gen_emit_float_cmp_op_guard('float_le', c.VFP_LE) - emit_guard_float_eq = gen_emit_float_cmp_op_guard('float_eq', c.EQ) - emit_guard_float_ne = gen_emit_float_cmp_op_guard('float_ne', c.NE) - emit_guard_float_gt = gen_emit_float_cmp_op_guard('float_gt', c.GT) - emit_guard_float_ge = gen_emit_float_cmp_op_guard('float_ge', c.GE) - def emit_op_cast_float_to_int(self, op, arglocs, regalloc, fcond): arg, res = arglocs assert arg.is_vfp_reg() diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -8,10 +8,12 @@ from rpython.jit.backend.arm import locations from rpython.jit.backend.arm.locations import imm, get_fp_offset from rpython.jit.backend.arm.helper.regalloc import (prepare_op_by_helper_call, - prepare_op_unary_cmp, + prepare_unary_cmp, prepare_op_ri, - prepare_cmp_op, - prepare_float_op, + prepare_int_cmp, + prepare_unary_op, + prepare_two_regs_op, + prepare_float_cmp, check_imm_arg, check_imm_box, VMEM_imm_size, @@ -146,6 +148,7 @@ box_types = None # or a list of acceptable types no_lower_byte_regs = all_regs save_around_call_regs = r.caller_resp + frame_reg = r.fp def __init__(self, longevity, frame_manager=None, assembler=None): RegisterManager.__init__(self, longevity, frame_manager, assembler) @@ -235,6 +238,18 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_allocate_reg_or_cc(self, var, forbidden_vars=[]): + assert var.type == INT + if self.next_op_can_accept_cc(self.operations, self.rm.position): + # hack: return the 'fp' location to mean "lives in CC". This + # fp will not actually be used, and the location will be freed + # after the next op as usual. + self.rm.force_allocate_frame_reg(var) + return r.fp + else: + # else, return a regular register (not fp). + return self.rm.force_allocate_reg(var) + def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): if v.type == FLOAT: return self.vfprm.try_allocate_reg(v, selected_reg, @@ -500,55 +515,30 @@ prepare_op_uint_rshift = prepare_op_ri('uint_rshift', imm_size=0x1F, allow_zero=False, commutative=False) - prepare_op_int_lt = prepare_cmp_op('int_lt') - prepare_op_int_le = prepare_cmp_op('int_le') - prepare_op_int_eq = prepare_cmp_op('int_eq') - prepare_op_int_ne = prepare_cmp_op('int_ne') - prepare_op_int_gt = prepare_cmp_op('int_gt') - prepare_op_int_ge = prepare_cmp_op('int_ge') + prepare_op_int_lt = prepare_int_cmp + prepare_op_int_le = prepare_int_cmp + prepare_op_int_eq = prepare_int_cmp + prepare_op_int_ne = prepare_int_cmp + prepare_op_int_gt = prepare_int_cmp + prepare_op_int_ge = prepare_int_cmp - prepare_op_uint_le = prepare_cmp_op('uint_le') - prepare_op_uint_gt = prepare_cmp_op('uint_gt') + prepare_op_uint_le = prepare_int_cmp + prepare_op_uint_gt = prepare_int_cmp - prepare_op_uint_lt = prepare_cmp_op('uint_lt') - prepare_op_uint_ge = prepare_cmp_op('uint_ge') + prepare_op_uint_lt = prepare_int_cmp + prepare_op_uint_ge = prepare_int_cmp prepare_op_ptr_eq = prepare_op_instance_ptr_eq = prepare_op_int_eq prepare_op_ptr_ne = prepare_op_instance_ptr_ne = prepare_op_int_ne - prepare_guard_int_lt = prepare_cmp_op('guard_int_lt') - prepare_guard_int_le = prepare_cmp_op('guard_int_le') - prepare_guard_int_eq = prepare_cmp_op('guard_int_eq') - prepare_guard_int_ne = prepare_cmp_op('guard_int_ne') - prepare_guard_int_gt = prepare_cmp_op('guard_int_gt') - prepare_guard_int_ge = prepare_cmp_op('guard_int_ge') - - prepare_guard_uint_le = prepare_cmp_op('guard_uint_le') - prepare_guard_uint_gt = prepare_cmp_op('guard_uint_gt') - - prepare_guard_uint_lt = prepare_cmp_op('guard_uint_lt') - prepare_guard_uint_ge = prepare_cmp_op('guard_uint_ge') - - prepare_guard_ptr_eq = prepare_guard_instance_ptr_eq = prepare_guard_int_eq - prepare_guard_ptr_ne = prepare_guard_instance_ptr_ne = prepare_guard_int_ne - prepare_op_int_add_ovf = prepare_op_int_add prepare_op_int_sub_ovf = prepare_op_int_sub - prepare_op_int_is_true = prepare_op_unary_cmp('int_is_true') - prepare_op_int_is_zero = prepare_op_unary_cmp('int_is_zero') + prepare_op_int_is_true = prepare_unary_cmp + prepare_op_int_is_zero = prepare_unary_cmp - prepare_guard_int_is_true = prepare_op_unary_cmp('int_is_true') - prepare_guard_int_is_zero = prepare_op_unary_cmp('int_is_zero') - - def prepare_op_int_neg(self, op, fcond): - l0 = self.make_sure_var_in_reg(op.getarg(0)) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - resloc = self.force_allocate_reg(op.result) - return [l0, resloc] - - prepare_op_int_invert = prepare_op_int_neg + prepare_op_int_neg = prepare_unary_op + prepare_op_int_invert = prepare_unary_op def prepare_op_call(self, op, fcond): effectinfo = op.getdescr().get_extra_info() @@ -1271,39 +1261,18 @@ arglocs.append(t) return arglocs - prepare_op_float_add = prepare_float_op(name='prepare_op_float_add') - prepare_op_float_sub = prepare_float_op(name='prepare_op_float_sub') - prepare_op_float_mul = prepare_float_op(name='prepare_op_float_mul') - prepare_op_float_truediv = prepare_float_op(name='prepare_op_float_truediv') - prepare_op_float_lt = prepare_float_op(float_result=False, - name='prepare_op_float_lt') - prepare_op_float_le = prepare_float_op(float_result=False, - name='prepare_op_float_le') - prepare_op_float_eq = prepare_float_op(float_result=False, - name='prepare_op_float_eq') - prepare_op_float_ne = prepare_float_op(float_result=False, - name='prepare_op_float_ne') - prepare_op_float_gt = prepare_float_op(float_result=False, - name='prepare_op_float_gt') - prepare_op_float_ge = prepare_float_op(float_result=False, - name='prepare_op_float_ge') - prepare_op_float_neg = prepare_float_op(base=False, - name='prepare_op_float_neg') - prepare_op_float_abs = prepare_float_op(base=False, - name='prepare_op_float_abs') - - prepare_guard_float_lt = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_lt') - prepare_guard_float_le = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_le') - prepare_guard_float_eq = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_eq') - prepare_guard_float_ne = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_ne') - prepare_guard_float_gt = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_gt') - prepare_guard_float_ge = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_ge') + prepare_op_float_add = prepare_two_regs_op + prepare_op_float_sub = prepare_two_regs_op + prepare_op_float_mul = prepare_two_regs_op + prepare_op_float_truediv = prepare_two_regs_op + prepare_op_float_lt = prepare_float_cmp + prepare_op_float_le = prepare_float_cmp + prepare_op_float_eq = prepare_float_cmp + prepare_op_float_ne = prepare_float_cmp + prepare_op_float_gt = prepare_float_cmp + prepare_op_float_ge = prepare_float_cmp + prepare_op_float_neg = prepare_unary_op + prepare_op_float_abs = prepare_unary_op def _prepare_op_math_sqrt(self, op, fcond): loc = self.make_sure_var_in_reg(op.getarg(1)) @@ -1327,10 +1296,8 @@ self.force_spill_var(op.getarg(0)) return [] - prepare_op_convert_float_bytes_to_longlong = prepare_float_op(base=False, - name='prepare_op_convert_float_bytes_to_longlong') - prepare_op_convert_longlong_bytes_to_float = prepare_float_op(base=False, - name='prepare_op_convert_longlong_bytes_to_float') + prepare_op_convert_float_bytes_to_longlong = prepare_unary_op + prepare_op_convert_longlong_bytes_to_float = prepare_unary_op #def prepare_op_read_timestamp(self, op, fcond): # loc = self.get_scratch_reg(INT) @@ -1348,22 +1315,12 @@ return [loc1, res] -def add_none_argument(fn): - return lambda self, op, fcond: fn(self, op, None, fcond) - - def notimplemented(self, op, fcond): print "[ARM/regalloc] %s not implemented" % op.getopname() raise NotImplementedError(op) -def notimplemented_with_guard(self, op, guard_op, fcond): - print "[ARM/regalloc] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - operations = [notimplemented] * (rop._LAST + 1) -operations_with_guard = [notimplemented_with_guard] * (rop._LAST + 1) for key, value in rop.__dict__.items(): @@ -1374,13 +1331,3 @@ if hasattr(Regalloc, methname): func = getattr(Regalloc, methname).im_func operations[value] = func - -for key, value in rop.__dict__.items(): - key = key.lower() - if key.startswith('_'): - continue - methname = 'prepare_guard_%s' % key - if hasattr(Regalloc, methname): - func = getattr(Regalloc, methname).im_func - operations_with_guard[value] = func - operations[value] = add_none_argument(func) From noreply at buildbot.pypy.org Fri Sep 4 18:16:35 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 18:16:35 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: arm: test_*_and_guards* Message-ID: <20150904161635.62AC41C14C3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79437:a1a3a320498a Date: 2015-09-04 18:16 +0200 http://bitbucket.org/pypy/pypy/changeset/a1a3a320498a/ Log: arm: test_*_and_guards* diff --git a/rpython/jit/backend/arm/conditions.py b/rpython/jit/backend/arm/conditions.py --- a/rpython/jit/backend/arm/conditions.py +++ b/rpython/jit/backend/arm/conditions.py @@ -19,6 +19,7 @@ def get_opposite_of(operation): + assert operation >= 0 return opposites[operation] # see mapping for floating poin according to diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -81,6 +81,7 @@ return fcond f.__name__ = 'emit_op_%s' % name return f + def gen_emit_unary_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -203,9 +203,15 @@ fcond=fcond) return token - def _emit_guard(self, op, arglocs, fcond, save_exc, + def _emit_guard(self, op, arglocs, save_exc, is_guard_not_invalidated=False, is_guard_not_forced=False): + if is_guard_not_invalidated: + fcond = c.cond_none + else: + fcond = self.guard_success_cc + self.guard_success_cc = c.cond_none + assert fcond != c.cond_none pos = self.mc.currpos() token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond, save_exc, is_guard_not_invalidated, @@ -231,17 +237,12 @@ return fcond def emit_op_guard_true(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.NE, save_exc=False) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_false(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.get_opposite_of(self.guard_success_cc) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_value(self, op, arglocs, regalloc, fcond): diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -5,6 +5,7 @@ RegisterManager, TempBox, compute_vars_longevity, BaseRegalloc, \ get_scale from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import locations from rpython.jit.backend.arm.locations import imm, get_fp_offset from rpython.jit.backend.arm.helper.regalloc import (prepare_op_by_helper_call, @@ -656,14 +657,25 @@ locs = [imm(fail_descr)] return locs - def prepare_op_guard_true(self, op, fcond): - l0 = self.make_sure_var_in_reg(op.getarg(0)) - args = self._prepare_guard(op, [l0]) + def load_condition_into_cc(self, box): + if self.assembler.guard_success_cc == c.cond_none: + loc = self.loc(box) + if not loc.is_core_reg(): + assert loc.is_stack() + self.assembler.regalloc_mov(loc, r.lr) + loc = r.lr + self.mc.CMP_ri(loc.value, 0) + self.assembler.guard_success_cc = c.NE + + def _prepare_guard_cc(self, op, fcond): + self.load_condition_into_cc(op.getarg(0)) + args = self._prepare_guard(op, []) return args - prepare_op_guard_false = prepare_op_guard_true - prepare_op_guard_nonnull = prepare_op_guard_true - prepare_op_guard_isnull = prepare_op_guard_true + prepare_op_guard_true = _prepare_guard_cc + prepare_op_guard_false = _prepare_guard_cc + prepare_op_guard_nonnull = _prepare_guard_cc + prepare_op_guard_isnull = _prepare_guard_cc def prepare_op_guard_value(self, op, fcond): boxes = op.getarglist() From noreply at buildbot.pypy.org Fri Sep 4 18:30:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 18:30:48 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: Minor refactor of int_xxx_ovf() Message-ID: <20150904163048.7FE231C2048@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79438:7e7fea339e9c Date: 2015-09-04 18:27 +0200 http://bitbucket.org/pypy/pypy/changeset/7e7fea339e9c/ Log: Minor refactor of int_xxx_ovf() diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1612,17 +1612,20 @@ mc.MOV(heap(self.cpu.pos_exc_value()), tmploc) mc.MOV(heap(self.cpu.pos_exception()), exctploc) - genop_int_add_ovf = genop_int_add - genop_int_sub_ovf = genop_int_sub - genop_int_mul_ovf = genop_int_mul + def genop_int_add_ovf(self, op, arglocs, resloc): + self.genop_int_add(op, arglocs, resloc) + self.guard_success_cc = rx86.Conditions['NO'] - def genop_guard_guard_no_overflow(self, guard_op, guard_token, locs, ign): + def genop_int_sub_ovf(self, op, arglocs, resloc): + self.genop_int_sub(op, arglocs, resloc) self.guard_success_cc = rx86.Conditions['NO'] - self.implement_guard(guard_token) - def genop_guard_guard_overflow(self, guard_op, guard_token, locs, ign): - self.guard_success_cc = rx86.Conditions['O'] - self.implement_guard(guard_token) + def genop_int_mul_ovf(self, op, arglocs, resloc): + self.genop_int_mul(op, arglocs, resloc) + self.guard_success_cc = rx86.Conditions['NO'] + + genop_guard_guard_no_overflow = genop_guard_guard_true + genop_guard_guard_overflow = genop_guard_guard_false def genop_guard_guard_value(self, guard_op, guard_token, locs, ign): if guard_op.getarg(0).type == FLOAT: From noreply at buildbot.pypy.org Fri Sep 4 18:30:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 18:30:50 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: arm: int_xxx_ovf Message-ID: <20150904163050.9221F1C2048@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79439:c3e40d50bd5c Date: 2015-09-04 18:30 +0200 http://bitbucket.org/pypy/pypy/changeset/c3e40d50bd5c/ Log: arm: int_xxx_ovf diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -111,32 +111,25 @@ return fcond #ref: http://blogs.arm.com/software-enablement/detecting-overflow-from-mul/ - def emit_guard_int_mul_ovf(self, op, guard, arglocs, regalloc, fcond): + def emit_op_int_mul_ovf(self, op, arglocs, regalloc, fcond): reg1 = arglocs[0] reg2 = arglocs[1] res = arglocs[2] - failargs = arglocs[3:] self.mc.SMULL(res.value, r.ip.value, reg1.value, reg2.value, cond=fcond) self.mc.CMP_rr(r.ip.value, res.value, shifttype=shift.ASR, imm=31, cond=fcond) - - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.NE, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.EQ, save_exc=False) - else: - assert 0 + self.guard_success_cc = c.EQ return fcond - def emit_guard_int_add_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_add_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_add_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_add_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond - def emit_guard_int_sub_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_sub_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_sub_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_sub_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond emit_op_int_floordiv = gen_emit_op_by_helper_call('int_floordiv', 'DIV') @@ -165,9 +158,6 @@ emit_op_ptr_eq = emit_op_instance_ptr_eq = emit_op_int_eq emit_op_ptr_ne = emit_op_instance_ptr_ne = emit_op_int_ne - emit_op_int_add_ovf = emit_op_int_add - emit_op_int_sub_ovf = emit_op_int_sub - emit_op_int_is_true = gen_emit_op_unary_cmp('int_is_true', c.NE) emit_op_int_is_zero = gen_emit_op_unary_cmp('int_is_zero', c.EQ) @@ -227,15 +217,6 @@ self.mc.BKPT() return c.AL - def _emit_guard_overflow(self, guard, failargs, fcond): - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VS, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VC, save_exc=False) - else: - assert 0 - return fcond - def emit_op_guard_true(self, op, arglocs, regalloc, fcond): fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond @@ -265,11 +246,8 @@ emit_op_guard_nonnull = emit_op_guard_true emit_op_guard_isnull = emit_op_guard_false - def emit_op_guard_no_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VC, save_exc=False) - - def emit_op_guard_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VS, save_exc=False) + emit_op_guard_no_overflow = emit_op_guard_true + emit_op_guard_overflow = emit_op_guard_false def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -483,25 +483,6 @@ resloc = self.force_allocate_reg(op.result) return [argloc, imm(numbytes), resloc] - def prepare_guard_int_mul_ovf(self, op, guard, fcond): - boxes = op.getarglist() - reg1 = self.make_sure_var_in_reg(boxes[0], forbidden_vars=boxes) - reg2 = self.make_sure_var_in_reg(boxes[1], forbidden_vars=boxes) - res = self.force_allocate_reg(op.result) - return self._prepare_guard(guard, [reg1, reg2, res]) - - def prepare_guard_int_add_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_add(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - - def prepare_guard_int_sub_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_sub(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') prepare_op_int_mod = prepare_op_by_helper_call('int_mod') prepare_op_uint_floordiv = prepare_op_by_helper_call('unit_floordiv') @@ -534,6 +515,7 @@ prepare_op_int_add_ovf = prepare_op_int_add prepare_op_int_sub_ovf = prepare_op_int_sub + prepare_op_int_mul_ovf = prepare_op_int_mul prepare_op_int_is_true = prepare_unary_cmp prepare_op_int_is_zero = prepare_unary_cmp @@ -699,6 +681,7 @@ prepare_op_guard_overflow = prepare_op_guard_no_overflow prepare_op_guard_not_invalidated = prepare_op_guard_no_overflow + prepare_op_guard_not_forced = prepare_op_guard_no_overflow def prepare_op_guard_exception(self, op, fcond): boxes = op.getarglist() From noreply at buildbot.pypy.org Fri Sep 4 19:00:19 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 19:00:19 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: arm: getting there Message-ID: <20150904170019.9E3C61C140E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79440:a0f8d5a277f9 Date: 2015-09-04 18:59 +0200 http://bitbucket.org/pypy/pypy/changeset/a0f8d5a277f9/ Log: arm: getting there diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -240,7 +240,8 @@ assert l1.is_vfp_reg() self.mc.VCMP(l0.value, l1.value) self.mc.VMRS(cond=fcond) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=False) return fcond emit_op_guard_nonnull = emit_op_guard_true @@ -251,13 +252,15 @@ def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): @@ -281,11 +284,13 @@ self._check_frame_depth_debug(self.mc) return fcond - def cond_call(self, op, gcmap, cond_loc, call_loc, fcond): + def emit_op_cond_call(self, op, arglocs, regalloc, fcond): + [call_loc] = arglocs + gcmap = regalloc.get_gcmap([call_loc]) + assert call_loc is r.r4 - self.mc.TST_rr(cond_loc.value, cond_loc.value) jmp_adr = self.mc.currpos() - self.mc.BKPT() # patched later + self.mc.BKPT() # patched later: the conditional jump # self.push_gcmap(self.mc, gcmap, store=True) # @@ -303,8 +308,13 @@ self.mc.BL(cond_call_adr) self.pop_gcmap(self.mc) # never any result value + cond = c.get_opposite_of(self.guard_success_cc) + self.guard_success_cc = c.cond_none pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) - pmc.B_offs(self.mc.currpos(), c.EQ) # equivalent to 0 as result of TST above + pmc.B_offs(self.mc.currpos(), cond) + # might be overridden again to skip over the following + # guard_no_exception too + self.previous_cond_call_jcond = jmp_adr, cond return fcond def emit_op_jump(self, op, arglocs, regalloc, fcond): @@ -400,8 +410,15 @@ failargs = arglocs[1:] self.mc.LDR_ri(loc.value, loc.value) self.mc.CMP_ri(loc.value, 0) - cond = self._emit_guard(op, failargs, c.EQ, save_exc=True) - return cond + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=True) + # If the previous operation was a COND_CALL, overwrite its conditional + # jump to jump over this GUARD_NO_EXCEPTION as well, if we can + if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: + jmp_adr, prev_cond = self.previous_cond_call_jcond + pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) + pmc.B_offs(self.mc.currpos(), prev_cond) + return fcond def emit_op_guard_exception(self, op, arglocs, regalloc, fcond): loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] @@ -410,7 +427,8 @@ self.mc.LDR_ri(r.ip.value, loc1.value) self.mc.CMP_rr(r.ip.value, loc.value) - self._emit_guard(op, failargs, c.EQ, save_exc=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, failargs, save_exc=True) self._store_and_reset_exception(self.mc, resloc) return fcond @@ -934,16 +952,14 @@ def imm(self, v): return imm(v) - def emit_guard_call_assembler(self, op, guard_op, arglocs, regalloc, - fcond): + def emit_op_call_assembler(self, op, arglocs, regalloc, fcond): if len(arglocs) == 4: [argloc, vloc, result_loc, tmploc] = arglocs else: [argloc, result_loc, tmploc] = arglocs vloc = imm(0) - self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) - self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op)) + self._store_force_index(self._find_nearby_operation(+1)) + self.call_assembler(op, argloc, vloc, result_loc, tmploc) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): @@ -1017,41 +1033,36 @@ mc.B(target) mc.copy_to_raw_memory(oldadr) - def emit_guard_call_may_force(self, op, guard_op, arglocs, regalloc, - fcond): - self._store_force_index(guard_op) - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] - # - self._emit_call(op, callargs, fcond=fcond) - self._emit_guard_may_force(guard_op, guardargs) - return fcond - - def _emit_guard_may_force(self, guard_op, arglocs): + def emit_op_guard_not_forced(self, op, arglocs, regalloc, fcond): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) - self._emit_guard(guard_op, arglocs, c.EQ, - save_exc=True, is_guard_not_forced=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) - def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, - fcond): - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] # extrat the arguments for the guard - self._store_force_index(guard_op) - self._emit_call(op, callargs, is_call_release_gil=True) - self._emit_guard_may_force(guard_op, guardargs) + def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, fcond=fcond) + return fcond + + def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, is_call_release_gil=True) return fcond def _store_force_index(self, guard_op): + assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or + guard_op.getopnum() == rop.GUARD_NOT_FORCED_2) faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') value = rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr)) self.mc.gen_load_int(r.ip.value, value) self.store_reg(self.mc, r.ip, r.fp, ofs) + def _find_nearby_operation(self, delta): + regalloc = self._regalloc + return regalloc.operations[regalloc.rm.position + delta] + def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): self.emit_op_call(op, arglocs, regalloc, fcond) self.propagate_memoryerror_if_r0_is_null() diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -524,7 +524,9 @@ prepare_op_int_invert = prepare_unary_op def prepare_op_call(self, op, fcond): - effectinfo = op.getdescr().get_extra_info() + calldescr = op.getdescr() + assert calldescr is not None + effectinfo = calldescr.get_extra_info() if effectinfo is not None: oopspecindex = effectinfo.oopspecindex if oopspecindex in (EffectInfo.OS_LLONG_ADD, @@ -576,13 +578,12 @@ def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls - self.vfprm.before_call(save_all_regs=save_all_regs) + self.vfprm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 - self.rm.before_call(save_all_regs=save_all_regs) - self.before_call_called = True + self.rm.before_call(force_store, save_all_regs=save_all_regs) resloc = None if op.result: resloc = self.after_call(op.result) @@ -1173,9 +1174,8 @@ arg = op.getarg(i) self.make_sure_var_in_reg(arg, args_so_far, selected_reg=reg) args_so_far.append(arg) - loc_cond = self.make_sure_var_in_reg(op.getarg(0), args_so_far) - gcmap = self.get_gcmap([tmpreg]) - self.assembler.cond_call(op, gcmap, loc_cond, tmpreg, fcond) + self.load_condition_into_cc(op.getarg(0)) + return [tmpreg] def prepare_op_force_token(self, op, fcond): # XXX for now we return a regular reg @@ -1229,15 +1229,13 @@ self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value) self.possibly_free_vars(op.getfailargs()) - def prepare_guard_call_may_force(self, op, guard_op, fcond): - args = self._prepare_call(op, save_all_regs=True) - return self._prepare_guard(guard_op, args) + def prepare_op_call_may_force(self, op, fcond): + return self._prepare_call(op, save_all_regs=True) - def prepare_guard_call_release_gil(self, op, guard_op, fcond): - args = self._prepare_call(op, save_all_regs=True, first_arg_index=2) - return self._prepare_guard(guard_op, args) + def prepare_op_call_release_gil(self, op, fcond): + return self._prepare_call(op, save_all_regs=True, first_arg_index=2) - def prepare_guard_call_assembler(self, op, guard_op, fcond): + def prepare_op_call_assembler(self, op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) From noreply at buildbot.pypy.org Fri Sep 4 19:21:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 19:21:13 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: kill jit-residual-call, a bit useless Message-ID: <20150904172113.6F18C1C050C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79441:030bab936ddf Date: 2015-09-04 19:21 +0200 http://bitbucket.org/pypy/pypy/changeset/030bab936ddf/ Log: kill jit-residual-call, a bit useless 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 @@ -1548,100 +1548,96 @@ def do_residual_call(self, funcbox, argboxes, descr, pc, assembler_call=False, assembler_call_jd=None): - debug_start("jit-residual-call") - try: - # First build allboxes: it may need some reordering from the - # list provided in argboxes, depending on the order in which - # the arguments are expected by the function - # - allboxes = self._build_allboxes(funcbox, argboxes, descr) - effectinfo = descr.get_extra_info() - if effectinfo.oopspecindex == effectinfo.OS_NOT_IN_TRACE: - return self.metainterp.do_not_in_trace_call(allboxes, descr) + # First build allboxes: it may need some reordering from the + # list provided in argboxes, depending on the order in which + # the arguments are expected by the function + # + allboxes = self._build_allboxes(funcbox, argboxes, descr) + effectinfo = descr.get_extra_info() + if effectinfo.oopspecindex == effectinfo.OS_NOT_IN_TRACE: + return self.metainterp.do_not_in_trace_call(allboxes, descr) - if (assembler_call or - effectinfo.check_forces_virtual_or_virtualizable()): - # residual calls require attention to keep virtualizables in-sync - self.metainterp.clear_exception() - if effectinfo.oopspecindex == EffectInfo.OS_JIT_FORCE_VIRTUAL: - resbox = self._do_jit_force_virtual(allboxes, descr, pc) - if resbox is not None: - return resbox - self.metainterp.vable_and_vrefs_before_residual_call() - tp = descr.get_result_type() - if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL: - resbox = self.metainterp.direct_libffi_call(allboxes, descr, - tp) - elif effectinfo.is_call_release_gil(): - resbox = self.metainterp.direct_call_release_gil(allboxes, - descr, tp) - elif tp == 'i': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_I, allboxes, descr=descr) + if (assembler_call or + effectinfo.check_forces_virtual_or_virtualizable()): + # residual calls require attention to keep virtualizables in-sync + self.metainterp.clear_exception() + if effectinfo.oopspecindex == EffectInfo.OS_JIT_FORCE_VIRTUAL: + resbox = self._do_jit_force_virtual(allboxes, descr, pc) + if resbox is not None: + return resbox + self.metainterp.vable_and_vrefs_before_residual_call() + tp = descr.get_result_type() + if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL: + resbox = self.metainterp.direct_libffi_call(allboxes, descr, + tp) + elif effectinfo.is_call_release_gil(): + resbox = self.metainterp.direct_call_release_gil(allboxes, + descr, tp) + elif tp == 'i': + resbox = self.metainterp.execute_and_record_varargs( + rop.CALL_MAY_FORCE_I, allboxes, descr=descr) + elif tp == 'r': + resbox = self.metainterp.execute_and_record_varargs( + rop.CALL_MAY_FORCE_R, allboxes, descr=descr) + elif tp == 'f': + resbox = self.metainterp.execute_and_record_varargs( + rop.CALL_MAY_FORCE_F, allboxes, descr=descr) + elif tp == 'v': + resbox = self.metainterp.execute_and_record_varargs( + rop.CALL_MAY_FORCE_N, allboxes, descr=descr) + else: + assert False + self.metainterp.vrefs_after_residual_call() + vablebox = None + if assembler_call: + vablebox, resbox = self.metainterp.direct_assembler_call( + assembler_call_jd) + if resbox and resbox.type != 'v': + self.make_result_of_lastop(resbox) + self.metainterp.vable_after_residual_call(funcbox) + self.metainterp.generate_guard(rop.GUARD_NOT_FORCED, None) + if vablebox is not None: + self.metainterp.history.record(rop.KEEPALIVE, [vablebox], None) + self.metainterp.handle_possible_exception() + return resbox + else: + effect = effectinfo.extraeffect + tp = descr.get_result_type() + if effect == effectinfo.EF_LOOPINVARIANT: + if tp == 'i': + return self.execute_varargs(rop.CALL_LOOPINVARIANT_I, + allboxes, + descr, False, False) elif tp == 'r': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_R, allboxes, descr=descr) + return self.execute_varargs(rop.CALL_LOOPINVARIANT_R, + allboxes, + descr, False, False) elif tp == 'f': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_F, allboxes, descr=descr) + return self.execute_varargs(rop.CALL_LOOPINVARIANT_F, + allboxes, + descr, False, False) elif tp == 'v': - resbox = self.metainterp.execute_and_record_varargs( - rop.CALL_MAY_FORCE_N, allboxes, descr=descr) + return self.execute_varargs(rop.CALL_LOOPINVARIANT_N, + allboxes, + descr, False, False) else: assert False - self.metainterp.vrefs_after_residual_call() - vablebox = None - if assembler_call: - vablebox, resbox = self.metainterp.direct_assembler_call( - assembler_call_jd) - if resbox and resbox.type != 'v': - self.make_result_of_lastop(resbox) - self.metainterp.vable_after_residual_call(funcbox) - self.metainterp.generate_guard(rop.GUARD_NOT_FORCED, None) - if vablebox is not None: - self.metainterp.history.record(rop.KEEPALIVE, [vablebox], None) - self.metainterp.handle_possible_exception() - return resbox + exc = effectinfo.check_can_raise() + pure = effectinfo.check_is_elidable() + if tp == 'i': + return self.execute_varargs(rop.CALL_I, allboxes, descr, + exc, pure) + elif tp == 'r': + return self.execute_varargs(rop.CALL_R, allboxes, descr, + exc, pure) + elif tp == 'f': + return self.execute_varargs(rop.CALL_F, allboxes, descr, + exc, pure) + elif tp == 'v': + return self.execute_varargs(rop.CALL_N, allboxes, descr, + exc, pure) else: - effect = effectinfo.extraeffect - tp = descr.get_result_type() - if effect == effectinfo.EF_LOOPINVARIANT: - if tp == 'i': - return self.execute_varargs(rop.CALL_LOOPINVARIANT_I, - allboxes, - descr, False, False) - elif tp == 'r': - return self.execute_varargs(rop.CALL_LOOPINVARIANT_R, - allboxes, - descr, False, False) - elif tp == 'f': - return self.execute_varargs(rop.CALL_LOOPINVARIANT_F, - allboxes, - descr, False, False) - elif tp == 'v': - return self.execute_varargs(rop.CALL_LOOPINVARIANT_N, - allboxes, - descr, False, False) - else: - assert False - exc = effectinfo.check_can_raise() - pure = effectinfo.check_is_elidable() - if tp == 'i': - return self.execute_varargs(rop.CALL_I, allboxes, descr, - exc, pure) - elif tp == 'r': - return self.execute_varargs(rop.CALL_R, allboxes, descr, - exc, pure) - elif tp == 'f': - return self.execute_varargs(rop.CALL_F, allboxes, descr, - exc, pure) - elif tp == 'v': - return self.execute_varargs(rop.CALL_N, allboxes, descr, - exc, pure) - else: - assert False - finally: - debug_stop("jit-residual-call") + assert False def do_conditional_call(self, condbox, funcbox, argboxes, descr, pc): if isinstance(condbox, ConstInt) and condbox.value == 0: From noreply at buildbot.pypy.org Fri Sep 4 19:36:53 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 19:36:53 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: fixes Message-ID: <20150904173653.C17321C1F5A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79442:2c8d7c4c0899 Date: 2015-09-04 19:08 +0200 http://bitbucket.org/pypy/pypy/changeset/2c8d7c4c0899/ Log: fixes diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1039,6 +1039,7 @@ self.mc.CMP_ri(r.ip.value, 0) self.guard_success_cc = c.EQ self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) + return fcond def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): self._store_force_index(self._find_nearby_operation(+1)) diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -647,7 +647,7 @@ assert loc.is_stack() self.assembler.regalloc_mov(loc, r.lr) loc = r.lr - self.mc.CMP_ri(loc.value, 0) + self.assembler.mc.CMP_ri(loc.value, 0) self.assembler.guard_success_cc = c.NE def _prepare_guard_cc(self, op, fcond): @@ -1236,10 +1236,9 @@ return self._prepare_call(op, save_all_regs=True, first_arg_index=2) def prepare_op_call_assembler(self, op, fcond): - locs = self.locs_for_call_assembler(op, guard_op) + locs = self.locs_for_call_assembler(op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) - self.possibly_free_vars(guard_op.getfailargs()) return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): From noreply at buildbot.pypy.org Fri Sep 4 19:43:34 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 19:43:34 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: Unsure if someone still uses --run-translation-tests and would explode Message-ID: <20150904174334.BF90B1C0207@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79443:9c0990386229 Date: 2015-09-04 19:43 +0200 http://bitbucket.org/pypy/pypy/changeset/9c0990386229/ Log: Unsure if someone still uses --run-translation-tests and would explode if this option was not recognized any more. But it is ignored anyway. diff --git a/rpython/jit/backend/arm/test/conftest.py b/rpython/jit/backend/arm/test/conftest.py --- a/rpython/jit/backend/arm/test/conftest.py +++ b/rpython/jit/backend/arm/test/conftest.py @@ -9,12 +9,14 @@ cpu = detect_cpu.autodetect() def pytest_addoption(parser): + # XXX nowadays, use the command line argument "--slow" + group = parser.getgroup('translation test options') group.addoption('--run-translation-tests', action="store_true", default=False, dest="run_translation_tests", - help="run tests that translate code") + help="THIS OPTION IS IGNORED, USE ``--slow''") def pytest_collect_directory(path, parent): if not cpu.startswith('arm'): From noreply at buildbot.pypy.org Fri Sep 4 19:49:04 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 19:49:04 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: fix Message-ID: <20150904174904.D50B41C1F97@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79444:69257123f94d Date: 2015-09-04 19:49 +0200 http://bitbucket.org/pypy/pypy/changeset/69257123f94d/ Log: fix diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -277,7 +277,7 @@ self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - return self._emit_guard(op, locs, fcond, save_exc=False, + return self._emit_guard(op, locs, save_exc=False, is_guard_not_invalidated=True) def emit_op_label(self, op, arglocs, regalloc, fcond): From noreply at buildbot.pypy.org Fri Sep 4 19:52:16 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 19:52:16 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: Kill option Message-ID: <20150904175216.4B8F81C1FA5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79445:242b99309986 Date: 2015-09-04 19:52 +0200 http://bitbucket.org/pypy/pypy/changeset/242b99309986/ Log: Kill option diff --git a/rpython/jit/backend/arm/test/conftest.py b/rpython/jit/backend/arm/test/conftest.py --- a/rpython/jit/backend/arm/test/conftest.py +++ b/rpython/jit/backend/arm/test/conftest.py @@ -1,23 +1,12 @@ """ -This conftest adds an option to run the translation tests which by default will -be disabled. -Also it disables the backend tests on non ARMv7 platforms +This disables the backend tests on non ARMv7 platforms. +Note that you need "--slow" to run translation tests. """ import py, os from rpython.jit.backend import detect_cpu cpu = detect_cpu.autodetect() -def pytest_addoption(parser): - # XXX nowadays, use the command line argument "--slow" - - group = parser.getgroup('translation test options') - group.addoption('--run-translation-tests', - action="store_true", - default=False, - dest="run_translation_tests", - help="THIS OPTION IS IGNORED, USE ``--slow''") - def pytest_collect_directory(path, parent): if not cpu.startswith('arm'): py.test.skip("ARM(v7) tests skipped: cpu is %r" % (cpu,)) From noreply at buildbot.pypy.org Fri Sep 4 20:08:57 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 4 Sep 2015 20:08:57 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: in retrace I don't want to care if importing the state caused the wrong virtual state, we should not have retraced in the first place Message-ID: <20150904180857.E0AD41C205F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79446:d2892f472080 Date: 2015-09-04 20:09 +0200 http://bitbucket.org/pypy/pypy/changeset/d2892f472080/ Log: in retrace I don't want to care if importing the state caused the wrong virtual state, we should not have retraced in the first place diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -124,7 +124,10 @@ def optimize_peeled_loop(self, start_label, end_jump, ops, state, call_pure_results, inline_short_preamble=True): self._check_no_forwarding([[start_label, end_jump], ops]) - label_args = self.import_state(start_label, state) + try: + label_args = self.import_state(start_label, state) + except VirtualStatesCantMatch: + raise InvalidLoop self.potential_extra_ops = {} self.optimizer.init_inparg_dict_from(label_args) info, _ = self.optimizer.propagate_all_forward( From noreply at buildbot.pypy.org Fri Sep 4 21:28:37 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 4 Sep 2015 21:28:37 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: fix, at least for llgraph Message-ID: <20150904192837.EEA391C1457@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79447:d7291feb2967 Date: 2015-09-04 21:28 +0200 http://bitbucket.org/pypy/pypy/changeset/d7291feb2967/ Log: fix, at least for llgraph diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2356,7 +2356,7 @@ ops = ''' [%s, %s, i3, i4] i2 = %s(%s) - cond_call(i2, ConstClass(func_ptr), i3, i4) + cond_call(i2, ConstClass(func_ptr), i3, i4, descr=calldescr) guard_no_exception(descr=faildescr) [] finish() ''' % ("i0" if operation.startswith('int') else "f0", @@ -2366,6 +2366,7 @@ "i0, i1" if operation.startswith('int') else "f0, f1")) loop = parse(ops, namespace={'func_ptr': func_ptr, + 'calldescr': calldescr, 'faildescr': BasicFailDescr()}) looptoken = JitCellToken() self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) From noreply at buildbot.pypy.org Sat Sep 5 10:56:16 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 10:56:16 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: improve the InvalidLoop messages Message-ID: <20150905085616.07B681C146A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79448:6ae66edb3037 Date: 2015-09-05 10:56 +0200 http://bitbucket.org/pypy/pypy/changeset/6ae66edb3037/ Log: improve the InvalidLoop messages diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -127,7 +127,7 @@ try: label_args = self.import_state(start_label, state) except VirtualStatesCantMatch: - raise InvalidLoop + raise InvalidLoop("Cannot import state, virtual states don't match") self.potential_extra_ops = {} self.optimizer.init_inparg_dict_from(label_args) info, _ = self.optimizer.propagate_all_forward( @@ -153,7 +153,9 @@ for arg in args: self.optimizer.force_box(arg) except VirtualStatesCantMatch: - raise InvalidLoop + raise InvalidLoop("Virtual states did not match " + "after picking the virtual state, when forcing" + " boxes") extra_same_as = self.short_preamble_producer.extra_same_as[:] target_token = self.finalize_short_preamble(label_op, state.virtual_state) From noreply at buildbot.pypy.org Sat Sep 5 11:03:35 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 11:03:35 +0200 (CEST) Subject: [pypy-commit] pypy optimize-cond-call: ready for merge Message-ID: <20150905090335.BBDE11C14DC@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optimize-cond-call Changeset: r79449:18f3ce86313f Date: 2015-09-05 10:59 +0200 http://bitbucket.org/pypy/pypy/changeset/18f3ce86313f/ Log: ready for merge From noreply at buildbot.pypy.org Sat Sep 5 11:03:38 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 11:03:38 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge optimize-cond-call Message-ID: <20150905090338.80D971C14DC@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79450:95f8d1976013 Date: 2015-09-05 11:03 +0200 http://bitbucket.org/pypy/pypy/changeset/95f8d1976013/ Log: hg merge optimize-cond-call Remove the merging of operations with the following guards, which removes some amount of messy code. Instead, operations like INT_EQ check if they should leave the result in the condition code; if so, the next GUARD_TRUE or GUARD_FALSE will pick up the condition code without producing any more code. Finally, this simpler arrangement allows COND_CALL to also pick up the condition code, which would have been a total mess before. diff too long, truncating to 2000 out of 2119 lines diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -12,8 +12,7 @@ from rpython.jit.backend.arm.opassembler import ResOpAssembler from rpython.jit.backend.arm.regalloc import (Regalloc, CoreRegisterManager, check_imm_arg, VFPRegisterManager, - operations as regalloc_operations, - operations_with_guard as regalloc_operations_with_guard) + operations as regalloc_operations) from rpython.jit.backend.llsupport import jitframe, rewrite from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER, debug_bridge, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale, valid_addressing_size @@ -645,8 +644,10 @@ size_excluding_failure_stuff - loop_head) def _assemble(self, regalloc, inputargs, operations): + self.guard_success_cc = c.cond_none regalloc.compute_hint_frame_locations(operations) self._walk_operations(inputargs, operations, regalloc) + assert self.guard_success_cc == c.cond_none frame_depth = regalloc.get_final_frame_depth() jump_target_descr = regalloc.jump_target_descr if jump_target_descr is not None: @@ -927,6 +928,7 @@ def _walk_operations(self, inputargs, operations, regalloc): fcond = c.AL self._regalloc = regalloc + regalloc.operations = operations while regalloc.position() < len(operations) - 1: regalloc.next_instruction() i = regalloc.position() @@ -935,18 +937,7 @@ opnum = op.getopnum() if op.has_no_side_effect() and op.result not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif self._regalloc.can_merge_with_next_guard(op, i, operations): - guard = operations[i + 1] - assert guard.is_guard() - arglocs = regalloc_operations_with_guard[opnum](regalloc, op, - guard, fcond) - fcond = asm_operations_with_guard[opnum](self, op, - guard, arglocs, regalloc, fcond) - assert fcond is not None - regalloc.next_instruction() - regalloc.possibly_free_vars_for_op(guard) - regalloc.possibly_free_vars(guard.getfailargs()) - elif not we_are_translated() and op.getopnum() == -124: + if not we_are_translated() and op.getopnum() == -124: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) @@ -962,6 +953,7 @@ regalloc.free_temp_vars() regalloc._check_invariants() self.mc.mark_op(None) # end of the loop + regalloc.operations = None def regalloc_emit_extra(self, op, arglocs, fcond, regalloc): # for calls to a function with a specifically-supported OS_xxx @@ -1516,21 +1508,11 @@ raise NotImplementedError(op) -def notimplemented_op_with_guard(self, op, guard_op, arglocs, regalloc, fcond): - print "[ARM/asm] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - asm_operations = [notimplemented_op] * (rop._LAST + 1) -asm_operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) asm_extra_operations = {} for name, value in ResOpAssembler.__dict__.iteritems(): - if name.startswith('emit_guard_'): - opname = name[len('emit_guard_'):] - num = getattr(rop, opname.upper()) - asm_operations_with_guard[num] = value - elif name.startswith('emit_opx_'): + if name.startswith('emit_opx_'): opname = name[len('emit_opx_'):] num = getattr(EffectInfo, 'OS_' + opname.upper()) asm_extra_operations[num] = value diff --git a/rpython/jit/backend/arm/conditions.py b/rpython/jit/backend/arm/conditions.py --- a/rpython/jit/backend/arm/conditions.py +++ b/rpython/jit/backend/arm/conditions.py @@ -13,11 +13,13 @@ GT = 0xC LE = 0xD AL = 0xE +cond_none = -1 opposites = [NE, EQ, CC, CS, PL, MI, VC, VS, LS, HI, LT, GE, LE, GT, AL] def get_opposite_of(operation): + assert operation >= 0 return opposites[operation] # see mapping for floating poin according to diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -6,33 +6,32 @@ from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop + +def flush_cc(asm, condition, result_loc): + # After emitting an instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to 'fp' by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert asm.guard_success_cc == c.cond_none + if result_loc is r.fp: + asm.guard_success_cc = condition + else: + asm.mc.MOV_ri(result_loc.value, 1, condition) + asm.mc.MOV_ri(result_loc.value, 0, c.get_opposite_of(condition)) + + def gen_emit_op_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None reg, res = arglocs self.mc.CMP_ri(reg.value, 0) - self.mc.MOV_ri(res.value, 1, true_cond) - self.mc.MOV_ri(res.value, 0, false_cond) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_guard_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert fcond is not None - assert guard is not None - reg = arglocs[0] - self.mc.CMP_ri(reg.value, 0) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[1:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_op_ri(name, opname): ri_op = getattr(InstrBuilder, '%s_ri' % opname) rr_op = getattr(InstrBuilder, '%s_rr' % opname) @@ -61,8 +60,7 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op(name, condition): - inv = c.get_opposite_of(condition) +def gen_emit_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs @@ -70,32 +68,11 @@ self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) else: self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=condition) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - l0 = arglocs[0] - l1 = arglocs[1] - assert l0.is_core_reg() - - if l1.is_imm(): - self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) - else: - self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - guard_opnum = guard.getopnum() - cond = true_cond - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): @@ -104,6 +81,7 @@ return fcond f.__name__ = 'emit_op_%s' % name return f + def gen_emit_unary_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): @@ -113,34 +91,16 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op(name, cond): - inv = c.get_opposite_of(cond) +def gen_emit_float_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): arg1, arg2, res = arglocs self.mc.VCMP(arg1.value, arg2.value) self.mc.VMRS(cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=cond) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - arg1 = arglocs[0] - arg2 = arglocs[1] - self.mc.VCMP(arg1.value, arg2.value) - self.mc.VMRS(cond=fcond) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - class saved_registers(object): def __init__(self, cb, regs_to_save, vfp_regs_to_save=None): diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -50,42 +50,28 @@ f.__name__ = name return f -def prepare_float_op(name=None, base=True, float_result=True, guard=False): - if guard: - def f(self, op, guard_op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - else: - args = self._prepare_guard(guard_op, locs) - return args - else: - def f(self, op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - if name: - f.__name__ = name - return f +def prepare_unary_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, res] + +def prepare_two_regs_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, loc2, res] + +def prepare_float_cmp(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [loc1, loc2, res] def prepare_op_by_helper_call(name): def f(self, op, fcond): @@ -106,43 +92,28 @@ f.__name__ = name return f -def prepare_cmp_op(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - boxes = list(op.getarglist()) - arg0, arg1 = boxes - imm_a1 = check_imm_box(arg1) +def prepare_int_cmp(self, op, fcond): + assert fcond is not None + boxes = list(op.getarglist()) + arg0, arg1 = boxes + imm_a1 = check_imm_box(arg1) - l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) - if imm_a1: - l1 = self.convert_to_imm(arg1) - else: - l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) + l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) + if imm_a1: + l1 = self.convert_to_imm(arg1) + else: + l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - args = self._prepare_guard(guard_op, [l0, l1]) - return args - if name: - f.__name__ = name - return f + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] -def prepare_op_unary_cmp(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - a0 = op.getarg(0) - assert isinstance(a0, Box) - reg = self.make_sure_var_in_reg(a0) - self.possibly_free_vars_for_op(op) - if guard_op is None: - res = self.force_allocate_reg(op.result, [a0]) - return [reg, res] - else: - return self._prepare_guard(guard_op, [reg]) - if name: - f.__name__ = name - return f +def prepare_unary_cmp(self, op, fcond): + assert fcond is not None + a0 = op.getarg(0) + assert isinstance(a0, Box) + reg = self.make_sure_var_in_reg(a0) + self.possibly_free_vars_for_op(op) + res = self.force_allocate_reg_or_cc(op.result) + return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -5,13 +5,10 @@ from rpython.jit.backend.arm.arch import WORD, DOUBLE_WORD, JITFRAME_FIXED_SIZE from rpython.jit.backend.arm.helper.assembler import (gen_emit_op_by_helper_call, gen_emit_op_unary_cmp, - gen_emit_guard_unary_cmp, gen_emit_op_ri, gen_emit_cmp_op, - gen_emit_cmp_op_guard, gen_emit_float_op, gen_emit_float_cmp_op, - gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg @@ -114,32 +111,25 @@ return fcond #ref: http://blogs.arm.com/software-enablement/detecting-overflow-from-mul/ - def emit_guard_int_mul_ovf(self, op, guard, arglocs, regalloc, fcond): + def emit_op_int_mul_ovf(self, op, arglocs, regalloc, fcond): reg1 = arglocs[0] reg2 = arglocs[1] res = arglocs[2] - failargs = arglocs[3:] self.mc.SMULL(res.value, r.ip.value, reg1.value, reg2.value, cond=fcond) self.mc.CMP_rr(r.ip.value, res.value, shifttype=shift.ASR, imm=31, cond=fcond) - - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.NE, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.EQ, save_exc=False) - else: - assert 0 + self.guard_success_cc = c.EQ return fcond - def emit_guard_int_add_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_add_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_add_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_add_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond - def emit_guard_int_sub_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_sub_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_sub_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_sub_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond emit_op_int_floordiv = gen_emit_op_by_helper_call('int_floordiv', 'DIV') @@ -160,37 +150,17 @@ emit_op_int_gt = gen_emit_cmp_op('int_gt', c.GT) emit_op_int_ge = gen_emit_cmp_op('int_ge', c.GE) - emit_guard_int_lt = gen_emit_cmp_op_guard('int_lt', c.LT) - emit_guard_int_le = gen_emit_cmp_op_guard('int_le', c.LE) - emit_guard_int_eq = gen_emit_cmp_op_guard('int_eq', c.EQ) - emit_guard_int_ne = gen_emit_cmp_op_guard('int_ne', c.NE) - emit_guard_int_gt = gen_emit_cmp_op_guard('int_gt', c.GT) - emit_guard_int_ge = gen_emit_cmp_op_guard('int_ge', c.GE) - emit_op_uint_le = gen_emit_cmp_op('uint_le', c.LS) emit_op_uint_gt = gen_emit_cmp_op('uint_gt', c.HI) emit_op_uint_lt = gen_emit_cmp_op('uint_lt', c.LO) emit_op_uint_ge = gen_emit_cmp_op('uint_ge', c.HS) - emit_guard_uint_le = gen_emit_cmp_op_guard('uint_le', c.LS) - emit_guard_uint_gt = gen_emit_cmp_op_guard('uint_gt', c.HI) - emit_guard_uint_lt = gen_emit_cmp_op_guard('uint_lt', c.LO) - emit_guard_uint_ge = gen_emit_cmp_op_guard('uint_ge', c.HS) - emit_op_ptr_eq = emit_op_instance_ptr_eq = emit_op_int_eq emit_op_ptr_ne = emit_op_instance_ptr_ne = emit_op_int_ne - emit_guard_ptr_eq = emit_guard_instance_ptr_eq = emit_guard_int_eq - emit_guard_ptr_ne = emit_guard_instance_ptr_ne = emit_guard_int_ne - - emit_op_int_add_ovf = emit_op_int_add - emit_op_int_sub_ovf = emit_op_int_sub emit_op_int_is_true = gen_emit_op_unary_cmp('int_is_true', c.NE) emit_op_int_is_zero = gen_emit_op_unary_cmp('int_is_zero', c.EQ) - emit_guard_int_is_true = gen_emit_guard_unary_cmp('int_is_true', c.NE) - emit_guard_int_is_zero = gen_emit_guard_unary_cmp('int_is_zero', c.EQ) - def emit_op_int_invert(self, op, arglocs, regalloc, fcond): reg, res = arglocs @@ -223,9 +193,15 @@ fcond=fcond) return token - def _emit_guard(self, op, arglocs, fcond, save_exc, + def _emit_guard(self, op, arglocs, save_exc, is_guard_not_invalidated=False, is_guard_not_forced=False): + if is_guard_not_invalidated: + fcond = c.cond_none + else: + fcond = self.guard_success_cc + self.guard_success_cc = c.cond_none + assert fcond != c.cond_none pos = self.mc.currpos() token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond, save_exc, is_guard_not_invalidated, @@ -241,27 +217,13 @@ self.mc.BKPT() return c.AL - def _emit_guard_overflow(self, guard, failargs, fcond): - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VS, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VC, save_exc=False) - else: - assert 0 - return fcond - def emit_op_guard_true(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.NE, save_exc=False) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_false(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.get_opposite_of(self.guard_success_cc) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_value(self, op, arglocs, regalloc, fcond): @@ -278,27 +240,27 @@ assert l1.is_vfp_reg() self.mc.VCMP(l0.value, l1.value) self.mc.VMRS(cond=fcond) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=False) return fcond emit_op_guard_nonnull = emit_op_guard_true emit_op_guard_isnull = emit_op_guard_false - def emit_op_guard_no_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VC, save_exc=False) - - def emit_op_guard_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VS, save_exc=False) + emit_op_guard_no_overflow = emit_op_guard_true + emit_op_guard_overflow = emit_op_guard_false def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): @@ -315,18 +277,20 @@ self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - return self._emit_guard(op, locs, fcond, save_exc=False, + return self._emit_guard(op, locs, save_exc=False, is_guard_not_invalidated=True) def emit_op_label(self, op, arglocs, regalloc, fcond): self._check_frame_depth_debug(self.mc) return fcond - def cond_call(self, op, gcmap, cond_loc, call_loc, fcond): + def emit_op_cond_call(self, op, arglocs, regalloc, fcond): + [call_loc] = arglocs + gcmap = regalloc.get_gcmap([call_loc]) + assert call_loc is r.r4 - self.mc.TST_rr(cond_loc.value, cond_loc.value) jmp_adr = self.mc.currpos() - self.mc.BKPT() # patched later + self.mc.BKPT() # patched later: the conditional jump # self.push_gcmap(self.mc, gcmap, store=True) # @@ -344,8 +308,13 @@ self.mc.BL(cond_call_adr) self.pop_gcmap(self.mc) # never any result value + cond = c.get_opposite_of(self.guard_success_cc) + self.guard_success_cc = c.cond_none pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) - pmc.B_offs(self.mc.currpos(), c.EQ) # equivalent to 0 as result of TST above + pmc.B_offs(self.mc.currpos(), cond) + # might be overridden again to skip over the following + # guard_no_exception too + self.previous_cond_call_jcond = jmp_adr, cond return fcond def emit_op_jump(self, op, arglocs, regalloc, fcond): @@ -441,8 +410,15 @@ failargs = arglocs[1:] self.mc.LDR_ri(loc.value, loc.value) self.mc.CMP_ri(loc.value, 0) - cond = self._emit_guard(op, failargs, c.EQ, save_exc=True) - return cond + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=True) + # If the previous operation was a COND_CALL, overwrite its conditional + # jump to jump over this GUARD_NO_EXCEPTION as well, if we can + if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: + jmp_adr, prev_cond = self.previous_cond_call_jcond + pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) + pmc.B_offs(self.mc.currpos(), prev_cond) + return fcond def emit_op_guard_exception(self, op, arglocs, regalloc, fcond): loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] @@ -451,7 +427,8 @@ self.mc.LDR_ri(r.ip.value, loc1.value) self.mc.CMP_rr(r.ip.value, loc.value) - self._emit_guard(op, failargs, c.EQ, save_exc=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, failargs, save_exc=True) self._store_and_reset_exception(self.mc, resloc) return fcond @@ -975,16 +952,14 @@ def imm(self, v): return imm(v) - def emit_guard_call_assembler(self, op, guard_op, arglocs, regalloc, - fcond): + def emit_op_call_assembler(self, op, arglocs, regalloc, fcond): if len(arglocs) == 4: [argloc, vloc, result_loc, tmploc] = arglocs else: [argloc, result_loc, tmploc] = arglocs vloc = imm(0) - self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) - self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op)) + self._store_force_index(self._find_nearby_operation(+1)) + self.call_assembler(op, argloc, vloc, result_loc, tmploc) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): @@ -1058,41 +1033,37 @@ mc.B(target) mc.copy_to_raw_memory(oldadr) - def emit_guard_call_may_force(self, op, guard_op, arglocs, regalloc, - fcond): - self._store_force_index(guard_op) - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] - # - self._emit_call(op, callargs, fcond=fcond) - self._emit_guard_may_force(guard_op, guardargs) - return fcond - - def _emit_guard_may_force(self, guard_op, arglocs): + def emit_op_guard_not_forced(self, op, arglocs, regalloc, fcond): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) - self._emit_guard(guard_op, arglocs, c.EQ, - save_exc=True, is_guard_not_forced=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) + return fcond - def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, - fcond): - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] # extrat the arguments for the guard - self._store_force_index(guard_op) - self._emit_call(op, callargs, is_call_release_gil=True) - self._emit_guard_may_force(guard_op, guardargs) + def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, fcond=fcond) + return fcond + + def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, is_call_release_gil=True) return fcond def _store_force_index(self, guard_op): + assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or + guard_op.getopnum() == rop.GUARD_NOT_FORCED_2) faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') value = rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr)) self.mc.gen_load_int(r.ip.value, value) self.store_reg(self.mc, r.ip, r.fp, ofs) + def _find_nearby_operation(self, delta): + regalloc = self._regalloc + return regalloc.operations[regalloc.rm.position + delta] + def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): self.emit_op_call(op, arglocs, regalloc, fcond) self.propagate_memoryerror_if_r0_is_null() @@ -1125,13 +1096,6 @@ emit_op_float_gt = gen_emit_float_cmp_op('float_gt', c.GT) emit_op_float_ge = gen_emit_float_cmp_op('float_ge', c.GE) - emit_guard_float_lt = gen_emit_float_cmp_op_guard('float_lt', c.VFP_LT) - emit_guard_float_le = gen_emit_float_cmp_op_guard('float_le', c.VFP_LE) - emit_guard_float_eq = gen_emit_float_cmp_op_guard('float_eq', c.EQ) - emit_guard_float_ne = gen_emit_float_cmp_op_guard('float_ne', c.NE) - emit_guard_float_gt = gen_emit_float_cmp_op_guard('float_gt', c.GT) - emit_guard_float_ge = gen_emit_float_cmp_op_guard('float_ge', c.GE) - def emit_op_cast_float_to_int(self, op, arglocs, regalloc, fcond): arg, res = arglocs assert arg.is_vfp_reg() diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -5,13 +5,16 @@ RegisterManager, TempBox, compute_vars_longevity, BaseRegalloc, \ get_scale from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import locations from rpython.jit.backend.arm.locations import imm, get_fp_offset from rpython.jit.backend.arm.helper.regalloc import (prepare_op_by_helper_call, - prepare_op_unary_cmp, + prepare_unary_cmp, prepare_op_ri, - prepare_cmp_op, - prepare_float_op, + prepare_int_cmp, + prepare_unary_op, + prepare_two_regs_op, + prepare_float_cmp, check_imm_arg, check_imm_box, VMEM_imm_size, @@ -146,6 +149,7 @@ box_types = None # or a list of acceptable types no_lower_byte_regs = all_regs save_around_call_regs = r.caller_resp + frame_reg = r.fp def __init__(self, longevity, frame_manager=None, assembler=None): RegisterManager.__init__(self, longevity, frame_manager, assembler) @@ -235,6 +239,18 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_allocate_reg_or_cc(self, var, forbidden_vars=[]): + assert var.type == INT + if self.next_op_can_accept_cc(self.operations, self.rm.position): + # hack: return the 'fp' location to mean "lives in CC". This + # fp will not actually be used, and the location will be freed + # after the next op as usual. + self.rm.force_allocate_frame_reg(var) + return r.fp + else: + # else, return a regular register (not fp). + return self.rm.force_allocate_reg(var) + def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): if v.type == FLOAT: return self.vfprm.try_allocate_reg(v, selected_reg, @@ -467,25 +483,6 @@ resloc = self.force_allocate_reg(op.result) return [argloc, imm(numbytes), resloc] - def prepare_guard_int_mul_ovf(self, op, guard, fcond): - boxes = op.getarglist() - reg1 = self.make_sure_var_in_reg(boxes[0], forbidden_vars=boxes) - reg2 = self.make_sure_var_in_reg(boxes[1], forbidden_vars=boxes) - res = self.force_allocate_reg(op.result) - return self._prepare_guard(guard, [reg1, reg2, res]) - - def prepare_guard_int_add_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_add(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - - def prepare_guard_int_sub_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_sub(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') prepare_op_int_mod = prepare_op_by_helper_call('int_mod') prepare_op_uint_floordiv = prepare_op_by_helper_call('unit_floordiv') @@ -500,58 +497,36 @@ prepare_op_uint_rshift = prepare_op_ri('uint_rshift', imm_size=0x1F, allow_zero=False, commutative=False) - prepare_op_int_lt = prepare_cmp_op('int_lt') - prepare_op_int_le = prepare_cmp_op('int_le') - prepare_op_int_eq = prepare_cmp_op('int_eq') - prepare_op_int_ne = prepare_cmp_op('int_ne') - prepare_op_int_gt = prepare_cmp_op('int_gt') - prepare_op_int_ge = prepare_cmp_op('int_ge') + prepare_op_int_lt = prepare_int_cmp + prepare_op_int_le = prepare_int_cmp + prepare_op_int_eq = prepare_int_cmp + prepare_op_int_ne = prepare_int_cmp + prepare_op_int_gt = prepare_int_cmp + prepare_op_int_ge = prepare_int_cmp - prepare_op_uint_le = prepare_cmp_op('uint_le') - prepare_op_uint_gt = prepare_cmp_op('uint_gt') + prepare_op_uint_le = prepare_int_cmp + prepare_op_uint_gt = prepare_int_cmp - prepare_op_uint_lt = prepare_cmp_op('uint_lt') - prepare_op_uint_ge = prepare_cmp_op('uint_ge') + prepare_op_uint_lt = prepare_int_cmp + prepare_op_uint_ge = prepare_int_cmp prepare_op_ptr_eq = prepare_op_instance_ptr_eq = prepare_op_int_eq prepare_op_ptr_ne = prepare_op_instance_ptr_ne = prepare_op_int_ne - prepare_guard_int_lt = prepare_cmp_op('guard_int_lt') - prepare_guard_int_le = prepare_cmp_op('guard_int_le') - prepare_guard_int_eq = prepare_cmp_op('guard_int_eq') - prepare_guard_int_ne = prepare_cmp_op('guard_int_ne') - prepare_guard_int_gt = prepare_cmp_op('guard_int_gt') - prepare_guard_int_ge = prepare_cmp_op('guard_int_ge') - - prepare_guard_uint_le = prepare_cmp_op('guard_uint_le') - prepare_guard_uint_gt = prepare_cmp_op('guard_uint_gt') - - prepare_guard_uint_lt = prepare_cmp_op('guard_uint_lt') - prepare_guard_uint_ge = prepare_cmp_op('guard_uint_ge') - - prepare_guard_ptr_eq = prepare_guard_instance_ptr_eq = prepare_guard_int_eq - prepare_guard_ptr_ne = prepare_guard_instance_ptr_ne = prepare_guard_int_ne - prepare_op_int_add_ovf = prepare_op_int_add prepare_op_int_sub_ovf = prepare_op_int_sub + prepare_op_int_mul_ovf = prepare_op_int_mul - prepare_op_int_is_true = prepare_op_unary_cmp('int_is_true') - prepare_op_int_is_zero = prepare_op_unary_cmp('int_is_zero') + prepare_op_int_is_true = prepare_unary_cmp + prepare_op_int_is_zero = prepare_unary_cmp - prepare_guard_int_is_true = prepare_op_unary_cmp('int_is_true') - prepare_guard_int_is_zero = prepare_op_unary_cmp('int_is_zero') - - def prepare_op_int_neg(self, op, fcond): - l0 = self.make_sure_var_in_reg(op.getarg(0)) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - resloc = self.force_allocate_reg(op.result) - return [l0, resloc] - - prepare_op_int_invert = prepare_op_int_neg + prepare_op_int_neg = prepare_unary_op + prepare_op_int_invert = prepare_unary_op def prepare_op_call(self, op, fcond): - effectinfo = op.getdescr().get_extra_info() + calldescr = op.getdescr() + assert calldescr is not None + effectinfo = calldescr.get_extra_info() if effectinfo is not None: oopspecindex = effectinfo.oopspecindex if oopspecindex in (EffectInfo.OS_LLONG_ADD, @@ -603,13 +578,12 @@ def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls - self.vfprm.before_call(save_all_regs=save_all_regs) + self.vfprm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 - self.rm.before_call(save_all_regs=save_all_regs) - self.before_call_called = True + self.rm.before_call(force_store, save_all_regs=save_all_regs) resloc = None if op.result: resloc = self.after_call(op.result) @@ -666,14 +640,25 @@ locs = [imm(fail_descr)] return locs - def prepare_op_guard_true(self, op, fcond): - l0 = self.make_sure_var_in_reg(op.getarg(0)) - args = self._prepare_guard(op, [l0]) + def load_condition_into_cc(self, box): + if self.assembler.guard_success_cc == c.cond_none: + loc = self.loc(box) + if not loc.is_core_reg(): + assert loc.is_stack() + self.assembler.regalloc_mov(loc, r.lr) + loc = r.lr + self.assembler.mc.CMP_ri(loc.value, 0) + self.assembler.guard_success_cc = c.NE + + def _prepare_guard_cc(self, op, fcond): + self.load_condition_into_cc(op.getarg(0)) + args = self._prepare_guard(op, []) return args - prepare_op_guard_false = prepare_op_guard_true - prepare_op_guard_nonnull = prepare_op_guard_true - prepare_op_guard_isnull = prepare_op_guard_true + prepare_op_guard_true = _prepare_guard_cc + prepare_op_guard_false = _prepare_guard_cc + prepare_op_guard_nonnull = _prepare_guard_cc + prepare_op_guard_isnull = _prepare_guard_cc def prepare_op_guard_value(self, op, fcond): boxes = op.getarglist() @@ -697,6 +682,7 @@ prepare_op_guard_overflow = prepare_op_guard_no_overflow prepare_op_guard_not_invalidated = prepare_op_guard_no_overflow + prepare_op_guard_not_forced = prepare_op_guard_no_overflow def prepare_op_guard_exception(self, op, fcond): boxes = op.getarglist() @@ -1188,9 +1174,8 @@ arg = op.getarg(i) self.make_sure_var_in_reg(arg, args_so_far, selected_reg=reg) args_so_far.append(arg) - loc_cond = self.make_sure_var_in_reg(op.getarg(0), args_so_far) - gcmap = self.get_gcmap([tmpreg]) - self.assembler.cond_call(op, gcmap, loc_cond, tmpreg, fcond) + self.load_condition_into_cc(op.getarg(0)) + return [tmpreg] def prepare_op_force_token(self, op, fcond): # XXX for now we return a regular reg @@ -1244,19 +1229,16 @@ self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value) self.possibly_free_vars(op.getfailargs()) - def prepare_guard_call_may_force(self, op, guard_op, fcond): - args = self._prepare_call(op, save_all_regs=True) - return self._prepare_guard(guard_op, args) + def prepare_op_call_may_force(self, op, fcond): + return self._prepare_call(op, save_all_regs=True) - def prepare_guard_call_release_gil(self, op, guard_op, fcond): - args = self._prepare_call(op, save_all_regs=True, first_arg_index=2) - return self._prepare_guard(guard_op, args) + def prepare_op_call_release_gil(self, op, fcond): + return self._prepare_call(op, save_all_regs=True, first_arg_index=2) - def prepare_guard_call_assembler(self, op, guard_op, fcond): - locs = self.locs_for_call_assembler(op, guard_op) + def prepare_op_call_assembler(self, op, fcond): + locs = self.locs_for_call_assembler(op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) - self.possibly_free_vars(guard_op.getfailargs()) return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): @@ -1271,39 +1253,18 @@ arglocs.append(t) return arglocs - prepare_op_float_add = prepare_float_op(name='prepare_op_float_add') - prepare_op_float_sub = prepare_float_op(name='prepare_op_float_sub') - prepare_op_float_mul = prepare_float_op(name='prepare_op_float_mul') - prepare_op_float_truediv = prepare_float_op(name='prepare_op_float_truediv') - prepare_op_float_lt = prepare_float_op(float_result=False, - name='prepare_op_float_lt') - prepare_op_float_le = prepare_float_op(float_result=False, - name='prepare_op_float_le') - prepare_op_float_eq = prepare_float_op(float_result=False, - name='prepare_op_float_eq') - prepare_op_float_ne = prepare_float_op(float_result=False, - name='prepare_op_float_ne') - prepare_op_float_gt = prepare_float_op(float_result=False, - name='prepare_op_float_gt') - prepare_op_float_ge = prepare_float_op(float_result=False, - name='prepare_op_float_ge') - prepare_op_float_neg = prepare_float_op(base=False, - name='prepare_op_float_neg') - prepare_op_float_abs = prepare_float_op(base=False, - name='prepare_op_float_abs') - - prepare_guard_float_lt = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_lt') - prepare_guard_float_le = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_le') - prepare_guard_float_eq = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_eq') - prepare_guard_float_ne = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_ne') - prepare_guard_float_gt = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_gt') - prepare_guard_float_ge = prepare_float_op(guard=True, - float_result=False, name='prepare_guard_float_ge') + prepare_op_float_add = prepare_two_regs_op + prepare_op_float_sub = prepare_two_regs_op + prepare_op_float_mul = prepare_two_regs_op + prepare_op_float_truediv = prepare_two_regs_op + prepare_op_float_lt = prepare_float_cmp + prepare_op_float_le = prepare_float_cmp + prepare_op_float_eq = prepare_float_cmp + prepare_op_float_ne = prepare_float_cmp + prepare_op_float_gt = prepare_float_cmp + prepare_op_float_ge = prepare_float_cmp + prepare_op_float_neg = prepare_unary_op + prepare_op_float_abs = prepare_unary_op def _prepare_op_math_sqrt(self, op, fcond): loc = self.make_sure_var_in_reg(op.getarg(1)) @@ -1327,10 +1288,8 @@ self.force_spill_var(op.getarg(0)) return [] - prepare_op_convert_float_bytes_to_longlong = prepare_float_op(base=False, - name='prepare_op_convert_float_bytes_to_longlong') - prepare_op_convert_longlong_bytes_to_float = prepare_float_op(base=False, - name='prepare_op_convert_longlong_bytes_to_float') + prepare_op_convert_float_bytes_to_longlong = prepare_unary_op + prepare_op_convert_longlong_bytes_to_float = prepare_unary_op #def prepare_op_read_timestamp(self, op, fcond): # loc = self.get_scratch_reg(INT) @@ -1348,22 +1307,12 @@ return [loc1, res] -def add_none_argument(fn): - return lambda self, op, fcond: fn(self, op, None, fcond) - - def notimplemented(self, op, fcond): print "[ARM/regalloc] %s not implemented" % op.getopname() raise NotImplementedError(op) -def notimplemented_with_guard(self, op, guard_op, fcond): - print "[ARM/regalloc] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - operations = [notimplemented] * (rop._LAST + 1) -operations_with_guard = [notimplemented_with_guard] * (rop._LAST + 1) for key, value in rop.__dict__.items(): @@ -1374,13 +1323,3 @@ if hasattr(Regalloc, methname): func = getattr(Regalloc, methname).im_func operations[value] = func - -for key, value in rop.__dict__.items(): - key = key.lower() - if key.startswith('_'): - continue - methname = 'prepare_guard_%s' % key - if hasattr(Regalloc, methname): - func = getattr(Regalloc, methname).im_func - operations_with_guard[value] = func - operations[value] = add_none_argument(func) diff --git a/rpython/jit/backend/arm/test/conftest.py b/rpython/jit/backend/arm/test/conftest.py --- a/rpython/jit/backend/arm/test/conftest.py +++ b/rpython/jit/backend/arm/test/conftest.py @@ -1,21 +1,12 @@ """ -This conftest adds an option to run the translation tests which by default will -be disabled. -Also it disables the backend tests on non ARMv7 platforms +This disables the backend tests on non ARMv7 platforms. +Note that you need "--slow" to run translation tests. """ import py, os from rpython.jit.backend import detect_cpu cpu = detect_cpu.autodetect() -def pytest_addoption(parser): - group = parser.getgroup('translation test options') - group.addoption('--run-translation-tests', - action="store_true", - default=False, - dest="run_translation_tests", - help="run tests that translate code") - def pytest_collect_directory(path, parent): if not cpu.startswith('arm'): py.test.skip("ARM(v7) tests skipped: cpu is %r" % (cpu,)) diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -212,8 +212,7 @@ self.codemap_builder.leave_portal_frame(op.getarg(0).getint(), self.mc.get_relative_pos()) - def call_assembler(self, op, guard_op, argloc, vloc, result_loc, tmploc): - self._store_force_index(guard_op) + def call_assembler(self, op, argloc, vloc, result_loc, tmploc): descr = op.getdescr() assert isinstance(descr, JitCellToken) # @@ -262,9 +261,6 @@ # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location) - # XXX here should be emitted guard_not_forced, but due - # to incompatibilities in how it's done, we leave it for the - # caller to deal with @specialize.argtype(1) def _inject_debugging_code(self, looptoken, operations, tp, number): diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py --- a/rpython/jit/backend/llsupport/regalloc.py +++ b/rpython/jit/backend/llsupport/regalloc.py @@ -639,31 +639,26 @@ if looptoken.compiled_loop_token is not None: # <- for tests looptoken.compiled_loop_token._ll_initial_locs = locs - def can_merge_with_next_guard(self, op, i, operations): - if (op.getopnum() == rop.CALL_MAY_FORCE or - op.getopnum() == rop.CALL_ASSEMBLER or - op.getopnum() == rop.CALL_RELEASE_GIL): - assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED - return True - if not op.is_comparison(): - if op.is_ovf(): - if (operations[i + 1].getopnum() != rop.GUARD_NO_OVERFLOW and - operations[i + 1].getopnum() != rop.GUARD_OVERFLOW): - not_implemented("int_xxx_ovf not followed by " - "guard_(no)_overflow") - return True + def next_op_can_accept_cc(self, operations, i): + op = operations[i] + next_op = operations[i + 1] + opnum = next_op.getopnum() + if (opnum != rop.GUARD_TRUE and opnum != rop.GUARD_FALSE + and opnum != rop.COND_CALL): return False - if (operations[i + 1].getopnum() != rop.GUARD_TRUE and - operations[i + 1].getopnum() != rop.GUARD_FALSE): + if next_op.getarg(0) is not op.result: return False - if operations[i + 1].getarg(0) is not op.result: + if self.longevity[op.result][1] > i + 1: return False - if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].getfailargs()): - return False + if opnum != rop.COND_CALL: + if op.result in operations[i + 1].getfailargs(): + return False + else: + if op.result in operations[i + 1].getarglist()[1:]: + return False return True - def locs_for_call_assembler(self, op, guard_op): + def locs_for_call_assembler(self, op): descr = op.getdescr() assert isinstance(descr, JitCellToken) if op.numargs() == 2: diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2293,7 +2293,7 @@ value |= 32768 assert s.data.tid == value - def test_cond_call(self): + def test_cond_call_1(self): def func_void(*args): called.append(args) @@ -2330,6 +2330,52 @@ assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2 assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4 + def test_cond_call_2(self): + def func_void(*args): + called.append(args) + + FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, + EffectInfo.MOST_GENERAL) + + for (operation, arg1, arg2_if_true, arg2_if_false) in [ + ('int_lt', -5, 2, -5), + ('int_le', 5, 5, -6), + ('int_eq', 11, 11, 12), + ('int_ne', 11, 12, 11), + ('int_gt', 8, -1, 8), + ('int_xor', 7, 3, 7), # test without a comparison at all + ('int_is_true', 4242, 1, 0), + ('int_is_zero', 4242, 0, 1), + ('float_lt', -0.5, 0.2, -0.5), + ('float_eq', 1.1, 1.1, 1.2), + ]: + called = [] + + ops = ''' + [%s, %s, i3, i4] + i2 = %s(%s) + cond_call(i2, ConstClass(func_ptr), i3, i4, descr=calldescr) + guard_no_exception(descr=faildescr) [] + finish() + ''' % ("i0" if operation.startswith('int') else "f0", + "i1" if operation.startswith('int') else "f1", + operation, + ("i1" if operation.startswith('int_is_') else + "i0, i1" if operation.startswith('int') else + "f0, f1")) + loop = parse(ops, namespace={'func_ptr': func_ptr, + 'calldescr': calldescr, + 'faildescr': BasicFailDescr()}) + looptoken = JitCellToken() + self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) + frame = self.cpu.execute_token(looptoken, arg1, arg2_if_false, 0, 0) + assert called == [] + frame = self.cpu.execute_token(looptoken, arg1, arg2_if_true, + 67, 89) + assert called == [(67, 89)] + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -726,8 +726,10 @@ def _assemble(self, regalloc, inputargs, operations): self._regalloc = regalloc + self.guard_success_cc = rx86.cond_none regalloc.compute_hint_frame_locations(operations) regalloc.walk_operations(inputargs, operations) + assert self.guard_success_cc == rx86.cond_none if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging frame_depth = regalloc.get_final_frame_depth() @@ -922,8 +924,8 @@ oopspecindex = effectinfo.oopspecindex genop_math_list[oopspecindex](self, op, arglocs, resloc) - def regalloc_perform_with_guard(self, op, guard_op, faillocs, - arglocs, resloc, frame_depth): + def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, + frame_depth): faildescr = guard_op.getdescr() assert isinstance(faildescr, AbstractFailDescr) failargs = guard_op.getfailargs() @@ -931,21 +933,12 @@ guard_token = self.implement_guard_recovery(guard_opnum, faildescr, failargs, faillocs, frame_depth) - if op is None: - dispatch_opnum = guard_opnum - else: - dispatch_opnum = op.getopnum() - genop_guard_list[dispatch_opnum](self, op, guard_op, guard_token, - arglocs, resloc) + genop_guard_list[guard_opnum](self, guard_op, guard_token, + arglocs, resloc) if not we_are_translated(): # must be added by the genop_guard_list[]() assert guard_token is self.pending_guard_tokens[-1] - def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, - frame_depth): - self.regalloc_perform_with_guard(None, guard_op, faillocs, arglocs, - resloc, frame_depth) - def load_effective_addr(self, sizereg, baseofs, scale, result, frm=imm0): self.mc.LEA(result, addr_add(frm, sizereg, baseofs, scale)) @@ -977,88 +970,70 @@ self.mc.LEA_rm(result_loc.value, (loc.value, delta)) return genop_binary_or_lea + def flush_cc(self, cond, result_loc): + # After emitting a instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to ebp by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert self.guard_success_cc == rx86.cond_none + if result_loc is ebp: + self.guard_success_cc = cond + else: + rl = result_loc.lowest8bits() + self.mc.SET_ir(cond, rl.value) + self.mc.MOVZX8_rr(result_loc.value, rl.value) + def _cmpop(cond, rev_cond): + cond = rx86.Conditions[cond] + rev_cond = rx86.Conditions[rev_cond] + # def genop_cmp(self, op, arglocs, result_loc): - rl = result_loc.lowest8bits() if isinstance(op.getarg(0), Const): self.mc.CMP(arglocs[1], arglocs[0]) - self.mc.SET_ir(rx86.Conditions[rev_cond], rl.value) + self.flush_cc(rev_cond, result_loc) else: self.mc.CMP(arglocs[0], arglocs[1]) - self.mc.SET_ir(rx86.Conditions[cond], rl.value) - self.mc.MOVZX8_rr(result_loc.value, rl.value) + self.flush_cc(cond, result_loc) return genop_cmp - def _cmpop_float(cond, rev_cond, is_ne=False): - def genop_cmp(self, op, arglocs, result_loc): - if isinstance(arglocs[0], RegLoc): + def _if_parity_clear_zero_and_carry(self): + self.mc.J_il8(rx86.Conditions['NP'], 0) + jnp_location = self.mc.get_relative_pos() + # CMP EBP, 0: as EBP cannot be null here, that operation should + # always clear zero and carry + self.mc.CMP_ri(ebp.value, 0) + # patch the JNP above + offset = self.mc.get_relative_pos() - jnp_location + assert 0 < offset <= 127 + self.mc.overwrite(jnp_location-1, chr(offset)) + + def _cmpop_float(cond, rev_cond): + is_ne = cond == 'NE' + need_direct_p = 'A' not in cond + need_rev_p = 'A' not in rev_cond + cond_contains_e = ('E' in cond) ^ ('N' in cond) + cond = rx86.Conditions[cond] + rev_cond = rx86.Conditions[rev_cond] + # + def genop_cmp_float(self, op, arglocs, result_loc): + if need_direct_p: + direct_case = not isinstance(arglocs[1], RegLoc) + else: + direct_case = isinstance(arglocs[0], RegLoc) + if direct_case: self.mc.UCOMISD(arglocs[0], arglocs[1]) checkcond = cond + need_p = need_direct_p else: self.mc.UCOMISD(arglocs[1], arglocs[0]) checkcond = rev_cond - - tmp1 = result_loc.lowest8bits() - if IS_X86_32: - tmp2 = result_loc.higher8bits() - elif IS_X86_64: - tmp2 = X86_64_SCRATCH_REG.lowest8bits() - - self.mc.SET_ir(rx86.Conditions[checkcond], tmp1.value) - if is_ne: - self.mc.SET_ir(rx86.Conditions['P'], tmp2.value) - self.mc.OR8_rr(tmp1.value, tmp2.value) - else: - self.mc.SET_ir(rx86.Conditions['NP'], tmp2.value) - self.mc.AND8_rr(tmp1.value, tmp2.value) - self.mc.MOVZX8_rr(result_loc.value, tmp1.value) - return genop_cmp - - def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond): - def genop_cmp_guard(self, op, guard_op, guard_token, arglocs, result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(op.getarg(0), Const): - self.mc.CMP(arglocs[1], arglocs[0]) - if guard_opnum == rop.GUARD_FALSE: - self.implement_guard(guard_token, rev_cond) - else: - self.implement_guard(guard_token, false_rev_cond) - else: - self.mc.CMP(arglocs[0], arglocs[1]) - if guard_opnum == rop.GUARD_FALSE: - self.implement_guard(guard_token, cond) - else: - self.implement_guard(guard_token, false_cond) - return genop_cmp_guard - - def _cmpop_guard_float(cond, rev_cond, false_cond, false_rev_cond): - need_direct_jp = 'A' not in cond - need_rev_jp = 'A' not in rev_cond - def genop_cmp_guard_float(self, op, guard_op, guard_token, arglocs, - result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(arglocs[0], RegLoc): - self.mc.UCOMISD(arglocs[0], arglocs[1]) - checkcond = cond - checkfalsecond = false_cond - need_jp = need_direct_jp - else: - self.mc.UCOMISD(arglocs[1], arglocs[0]) - checkcond = rev_cond - checkfalsecond = false_rev_cond - need_jp = need_rev_jp - if guard_opnum == rop.GUARD_FALSE: - if need_jp: - self.mc.J_il8(rx86.Conditions['P'], 6) - self.implement_guard(guard_token, checkcond) - else: - if need_jp: - self.mc.J_il8(rx86.Conditions['P'], 2) - self.mc.J_il8(rx86.Conditions[checkcond], 5) - self.implement_guard(guard_token) - else: - self.implement_guard(guard_token, checkfalsecond) - return genop_cmp_guard_float + need_p = need_rev_p + if need_p: + self._if_parity_clear_zero_and_carry() + self.flush_cc(checkcond, result_loc) + return genop_cmp_float def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: @@ -1121,37 +1096,17 @@ genop_ptr_eq = genop_instance_ptr_eq = genop_int_eq genop_ptr_ne = genop_instance_ptr_ne = genop_int_ne - genop_float_lt = _cmpop_float('B', 'A') - genop_float_le = _cmpop_float('BE', 'AE') - genop_float_ne = _cmpop_float('NE', 'NE', is_ne=True) - genop_float_eq = _cmpop_float('E', 'E') - genop_float_gt = _cmpop_float('A', 'B') - genop_float_ge = _cmpop_float('AE', 'BE') - genop_uint_gt = _cmpop("A", "B") genop_uint_lt = _cmpop("B", "A") genop_uint_le = _cmpop("BE", "AE") genop_uint_ge = _cmpop("AE", "BE") - genop_guard_int_lt = _cmpop_guard("L", "G", "GE", "LE") - genop_guard_int_le = _cmpop_guard("LE", "GE", "G", "L") - genop_guard_int_eq = _cmpop_guard("E", "E", "NE", "NE") - genop_guard_int_ne = _cmpop_guard("NE", "NE", "E", "E") - genop_guard_int_gt = _cmpop_guard("G", "L", "LE", "GE") - genop_guard_int_ge = _cmpop_guard("GE", "LE", "L", "G") - genop_guard_ptr_eq = genop_guard_instance_ptr_eq = genop_guard_int_eq - genop_guard_ptr_ne = genop_guard_instance_ptr_ne = genop_guard_int_ne - - genop_guard_uint_gt = _cmpop_guard("A", "B", "BE", "AE") - genop_guard_uint_lt = _cmpop_guard("B", "A", "AE", "BE") - genop_guard_uint_le = _cmpop_guard("BE", "AE", "A", "B") - genop_guard_uint_ge = _cmpop_guard("AE", "BE", "B", "A") - - genop_guard_float_lt = _cmpop_guard_float("B", "A", "AE","BE") - genop_guard_float_le = _cmpop_guard_float("BE","AE", "A", "B") - genop_guard_float_eq = _cmpop_guard_float("E", "E", "NE","NE") - genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE") - genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A") + genop_float_lt = _cmpop_float("B", "A") + genop_float_le = _cmpop_float("BE","AE") + genop_float_eq = _cmpop_float("E", "E") + genop_float_ne = _cmpop_float("NE", "NE") + genop_float_gt = _cmpop_float("A", "B") + genop_float_ge = _cmpop_float("AE","BE") def genop_math_sqrt(self, op, arglocs, resloc): self.mc.SQRTSD(arglocs[0], resloc) @@ -1181,20 +1136,6 @@ else: raise AssertionError("bad number of bytes") - def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(arglocs[0], RegLoc): - self.mc.UCOMISD(arglocs[0], arglocs[1]) - else: - self.mc.UCOMISD(arglocs[1], arglocs[0]) - if guard_opnum == rop.GUARD_TRUE: - self.mc.J_il8(rx86.Conditions['P'], 6) - self.implement_guard(guard_token, 'E') - else: - self.mc.J_il8(rx86.Conditions['P'], 2) - self.mc.J_il8(rx86.Conditions['E'], 5) - self.implement_guard(guard_token) - def genop_float_neg(self, op, arglocs, resloc): # Following what gcc does: res = x ^ 0x8000000000000000 self.mc.XORPD(arglocs[0], heap(self.float_const_neg_addr)) @@ -1241,33 +1182,20 @@ else: self.mov(loc0, resloc) - def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): - guard_opnum = guard_op.getopnum() - self.mc.CMP(arglocs[0], imm0) - if guard_opnum == rop.GUARD_TRUE: - self.implement_guard(guard_token, 'Z') + def test_location(self, loc): + assert not isinstance(loc, ImmedLoc) + if isinstance(loc, RegLoc): + self.mc.TEST_rr(loc.value, loc.value) # more compact else: - self.implement_guard(guard_token, 'NZ') + self.mc.CMP(loc, imm0) # works from memory too def genop_int_is_true(self, op, arglocs, resloc): - self.mc.CMP(arglocs[0], imm0) - rl = resloc.lowest8bits() - self.mc.SET_ir(rx86.Conditions['NE'], rl.value) - self.mc.MOVZX8(resloc, rl) - - def genop_guard_int_is_zero(self, op, guard_op, guard_token, arglocs, resloc): - guard_opnum = guard_op.getopnum() - self.mc.CMP(arglocs[0], imm0) - if guard_opnum == rop.GUARD_TRUE: - self.implement_guard(guard_token, 'NZ') - else: - self.implement_guard(guard_token, 'Z') + self.test_location(arglocs[0]) + self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_int_is_zero(self, op, arglocs, resloc): - self.mc.CMP(arglocs[0], imm0) - rl = resloc.lowest8bits() - self.mc.SET_ir(rx86.Conditions['E'], rl.value) - self.mc.MOVZX8(resloc, rl) + self.test_location(arglocs[0]) + self.flush_cc(rx86.Conditions['Z'], resloc) def genop_same_as(self, op, arglocs, resloc): self.mov(arglocs[0], resloc) @@ -1618,30 +1546,40 @@ self.mc.MOVD32_xr(resloc.value, eax.value) self.mc.PUNPCKLDQ_xx(resloc.value, loc1.value) - def genop_guard_guard_true(self, ign_1, guard_op, guard_token, locs, ign_2): - loc = locs[0] - self.mc.TEST(loc, loc) - self.implement_guard(guard_token, 'Z') + def genop_guard_guard_true(self, guard_op, guard_token, locs, resloc): + self.implement_guard(guard_token) genop_guard_guard_nonnull = genop_guard_guard_true - def genop_guard_guard_no_exception(self, ign_1, guard_op, guard_token, - locs, ign_2): + def genop_guard_guard_false(self, guard_op, guard_token, locs, resloc): + self.guard_success_cc = rx86.invert_condition(self.guard_success_cc) + self.implement_guard(guard_token) + genop_guard_guard_isnull = genop_guard_guard_false + + def genop_guard_guard_no_exception(self, guard_op, guard_token, locs, ign): self.mc.CMP(heap(self.cpu.pos_exception()), imm0) - self.implement_guard(guard_token, 'NZ') + self.guard_success_cc = rx86.Conditions['Z'] + self.implement_guard(guard_token) + # If the previous operation was a COND_CALL, overwrite its conditional + # jump to jump over this GUARD_NO_EXCEPTION as well, if we can + if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: + jmp_adr = self.previous_cond_call_jcond + offset = self.mc.get_relative_pos() - jmp_adr + if offset <= 127: + self.mc.overwrite(jmp_adr-1, chr(offset)) - def genop_guard_guard_not_invalidated(self, ign_1, guard_op, guard_token, - locs, ign_2): + def genop_guard_guard_not_invalidated(self, guard_op, guard_token, + locs, ign): pos = self.mc.get_relative_pos() + 1 # after potential jmp guard_token.pos_jump_offset = pos self.pending_guard_tokens.append(guard_token) - def genop_guard_guard_exception(self, ign_1, guard_op, guard_token, - locs, resloc): + def genop_guard_guard_exception(self, guard_op, guard_token, locs, resloc): loc = locs[0] loc1 = locs[1] self.mc.MOV(loc1, heap(self.cpu.pos_exception())) self.mc.CMP(loc1, loc) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) self._store_and_reset_exception(self.mc, resloc) def _store_and_reset_exception(self, mc, excvalloc=None, exctploc=None, @@ -1674,41 +1612,29 @@ mc.MOV(heap(self.cpu.pos_exc_value()), tmploc) mc.MOV(heap(self.cpu.pos_exception()), exctploc) - def _gen_guard_overflow(self, guard_op, guard_token): - guard_opnum = guard_op.getopnum() - if guard_opnum == rop.GUARD_NO_OVERFLOW: - self.implement_guard(guard_token, 'O') - elif guard_opnum == rop.GUARD_OVERFLOW: - self.implement_guard(guard_token, 'NO') - else: - not_implemented("int_xxx_ovf followed by %s" % - guard_op.getopname()) + def genop_int_add_ovf(self, op, arglocs, resloc): + self.genop_int_add(op, arglocs, resloc) + self.guard_success_cc = rx86.Conditions['NO'] - def genop_guard_int_add_ovf(self, op, guard_op, guard_token, arglocs, result_loc): - self.mc.ADD(arglocs[0], arglocs[1]) - return self._gen_guard_overflow(guard_op, guard_token) + def genop_int_sub_ovf(self, op, arglocs, resloc): + self.genop_int_sub(op, arglocs, resloc) + self.guard_success_cc = rx86.Conditions['NO'] - def genop_guard_int_sub_ovf(self, op, guard_op, guard_token, arglocs, result_loc): - self.mc.SUB(arglocs[0], arglocs[1]) - return self._gen_guard_overflow(guard_op, guard_token) + def genop_int_mul_ovf(self, op, arglocs, resloc): + self.genop_int_mul(op, arglocs, resloc) + self.guard_success_cc = rx86.Conditions['NO'] - def genop_guard_int_mul_ovf(self, op, guard_op, guard_token, arglocs, result_loc): - self.mc.IMUL(arglocs[0], arglocs[1]) - return self._gen_guard_overflow(guard_op, guard_token) + genop_guard_guard_no_overflow = genop_guard_guard_true + genop_guard_guard_overflow = genop_guard_guard_false - def genop_guard_guard_false(self, ign_1, guard_op, guard_token, locs, ign_2): - loc = locs[0] - self.mc.TEST(loc, loc) - self.implement_guard(guard_token, 'NZ') - genop_guard_guard_isnull = genop_guard_guard_false - - def genop_guard_guard_value(self, ign_1, guard_op, guard_token, locs, ign_2): + def genop_guard_guard_value(self, guard_op, guard_token, locs, ign): if guard_op.getarg(0).type == FLOAT: assert guard_op.getarg(1).type == FLOAT self.mc.UCOMISD(locs[0], locs[1]) else: self.mc.CMP(locs[0], locs[1]) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) def _cmp_guard_class(self, locs): offset = self.cpu.vtable_offset @@ -1743,12 +1669,12 @@ elif IS_X86_64: self.mc.CMP32_mi((locs[0].value, 0), expected_typeid) - def genop_guard_guard_class(self, ign_1, guard_op, guard_token, locs, ign_2): + def genop_guard_guard_class(self, guard_op, guard_token, locs, ign): self._cmp_guard_class(locs) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) - def genop_guard_guard_nonnull_class(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_nonnull_class(self, guard_op, guard_token, locs, ign): self.mc.CMP(locs[0], imm1) # Patched below self.mc.J_il8(rx86.Conditions['B'], 0) @@ -1759,7 +1685,8 @@ assert 0 < offset <= 127 self.mc.overwrite(jb_location-1, chr(offset)) # - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): @@ -1924,13 +1851,11 @@ # exit function self._call_footer() - def implement_guard(self, guard_token, condition=None): + def implement_guard(self, guard_token): # These jumps are patched later. - if condition: - self.mc.J_il(rx86.Conditions[condition], 0) - else: - self.mc.JMP_l(0) - self.mc.force_frame_size(DEFAULT_FRAME_BYTES) + assert self.guard_success_cc >= 0 + self.mc.J_il(rx86.invert_condition(self.guard_success_cc), 0) + self.guard_success_cc = rx86.cond_none guard_token.pos_jump_offset = self.mc.get_relative_pos() - 4 self.pending_guard_tokens.append(guard_token) @@ -1964,42 +1889,44 @@ cb.emit() def _store_force_index(self, guard_op): + assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or + guard_op.getopnum() == rop.GUARD_NOT_FORCED_2) faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') self.mc.MOV(raw_stack(ofs), imm(rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr)))) - def _emit_guard_not_forced(self, guard_token): + def _find_nearby_operation(self, delta): + regalloc = self._regalloc + return regalloc.operations[regalloc.rm.position + delta] + + def genop_guard_guard_not_forced(self, guard_op, guard_token, locs, resloc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.CMP_bi(ofs, 0) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) - def genop_guard_call_may_force(self, op, guard_op, guard_token, - arglocs, result_loc): - self._store_force_index(guard_op) + def genop_call_may_force(self, op, arglocs, result_loc): + self._store_force_index(self._find_nearby_operation(+1)) self._genop_call(op, arglocs, result_loc) - self._emit_guard_not_forced(guard_token) - def genop_guard_call_release_gil(self, op, guard_op, guard_token, - arglocs, result_loc): - self._store_force_index(guard_op) + def genop_call_release_gil(self, op, arglocs, result_loc): + self._store_force_index(self._find_nearby_operation(+1)) self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - self._emit_guard_not_forced(guard_token) def imm(self, v): return imm(v) # ------------------- CALL ASSEMBLER -------------------------- - def genop_guard_call_assembler(self, op, guard_op, guard_token, - arglocs, result_loc): + def genop_call_assembler(self, op, arglocs, result_loc): if len(arglocs) == 2: [argloc, vloc] = arglocs else: [argloc] = arglocs vloc = self.imm(0) - self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) - self._emit_guard_not_forced(guard_token) + self._store_force_index(self._find_nearby_operation(+1)) + self.call_assembler(op, argloc, vloc, result_loc, eax) def _call_assembler_emit_call(self, addr, argloc, _): threadlocal_loc = RawEspLoc(THREADLOCAL_OFS, INT) @@ -2200,10 +2127,9 @@ not_implemented("not implemented operation with res: %s" % op.getopname()) - def not_implemented_op_guard(self, op, guard_op, - failaddr, arglocs, resloc): + def not_implemented_op_guard(self, guard_op, guard_token, locs, resloc): not_implemented("not implemented operation (guard): %s" % - op.getopname()) + guard_op.getopname()) def closing_jump(self, target_token): target = target_token._ll_loop_code @@ -2216,10 +2142,12 @@ def label(self): self._check_frame_depth_debug(self.mc) - def cond_call(self, op, gcmap, loc_cond, imm_func, arglocs): - self.mc.TEST(loc_cond, loc_cond) - self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later + def cond_call(self, op, gcmap, imm_func, arglocs): + assert self.guard_success_cc >= 0 + self.mc.J_il8(rx86.invert_condition(self.guard_success_cc), 0) + # patched later jmp_adr = self.mc.get_relative_pos() + self.guard_success_cc = rx86.cond_none # self.push_gcmap(self.mc, gcmap, store=True) # @@ -2260,8 +2188,9 @@ offset = self.mc.get_relative_pos() - jmp_adr assert 0 < offset <= 127 self.mc.overwrite(jmp_adr-1, chr(offset)) - # XXX if the next operation is a GUARD_NO_EXCEPTION, we should - # somehow jump over it too in the fast path + # might be overridden again to skip over the following + # guard_no_exception too + self.previous_cond_call_jcond = jmp_adr def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, gcmap): assert size & (WORD-1) == 0 # must be correctly aligned @@ -2454,7 +2383,7 @@ opname = name[len('genop_discard_'):] num = getattr(rop, opname.upper()) genop_discard_list[num] = value - elif name.startswith('genop_guard_') and name != 'genop_guard_exception': + elif name.startswith('genop_guard_'): opname = name[len('genop_guard_'):] num = getattr(rop, opname.upper()) genop_guard_list[num] = value diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -215,6 +215,18 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_allocate_reg_or_cc(self, var): + assert var.type == INT + if self.next_op_can_accept_cc(self.operations, self.rm.position): + # hack: return the ebp location to mean "lives in CC". This + # ebp will not actually be used, and the location will be freed + # after the next op as usual. + self.rm.force_allocate_frame_reg(var) + return ebp + else: + # else, return a regular register (not ebp). + return self.rm.force_allocate_reg(var, need_lower_byte=True) + def force_spill_var(self, var): if var.type == FLOAT: return self.xrm.force_spill_var(var) @@ -278,20 +290,8 @@ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs)) self.assembler.regalloc_perform_math(op, arglocs, result_loc) - def locs_for_fail(self, guard_op): - return [self.loc(v) for v in guard_op.getfailargs()] - - def perform_with_guard(self, op, guard_op, arglocs, result_loc): - faillocs = self.locs_for_fail(guard_op) - self.rm.position += 1 - self.xrm.position += 1 - self.assembler.regalloc_perform_with_guard(op, guard_op, faillocs, - arglocs, result_loc, - self.fm.get_frame_depth()) - self.possibly_free_vars(guard_op.getfailargs()) - def perform_guard(self, guard_op, arglocs, result_loc): - faillocs = self.locs_for_fail(guard_op) + faillocs = [self.loc(v) for v in guard_op.getfailargs()] if not we_are_translated(): if result_loc is not None: self.assembler.dump('%s <- %s(%s)' % (result_loc, guard_op, @@ -310,7 +310,7 @@ def walk_operations(self, inputargs, operations): i = 0 - #self.operations = operations + self.operations = operations while i < len(operations): op = operations[i] self.assembler.mc.mark_op(op) @@ -321,10 +321,7 @@ i += 1 self.possibly_free_vars_for_op(op) continue - if self.can_merge_with_next_guard(op, i, operations): - oplist_with_guard[op.getopnum()](self, op, operations[i + 1]) - i += 1 - elif not we_are_translated() and op.getopnum() == -124: + if not we_are_translated() and op.getopnum() == -124: self._consider_force_spill(op) else: oplist[op.getopnum()](self, op) @@ -336,6 +333,7 @@ assert not self.xrm.reg_bindings self.flush_loop() self.assembler.mc.mark_op(None) # end of the loop + self.operations = None for arg in inputargs: self.possibly_free_var(arg) @@ -363,14 +361,19 @@ return self.xrm.loc(v) return self.rm.loc(v) - def _consider_guard(self, op): - loc = self.rm.make_sure_var_in_reg(op.getarg(0)) - self.perform_guard(op, [loc], None) + def load_condition_into_cc(self, box): + if self.assembler.guard_success_cc == rx86.cond_none: + self.assembler.test_location(self.loc(box)) + self.assembler.guard_success_cc = rx86.Conditions['NZ'] - consider_guard_true = _consider_guard - consider_guard_false = _consider_guard - consider_guard_nonnull = _consider_guard - consider_guard_isnull = _consider_guard + def _consider_guard_cc(self, op): + self.load_condition_into_cc(op.getarg(0)) + self.perform_guard(op, [], None) + + consider_guard_true = _consider_guard_cc + consider_guard_false = _consider_guard_cc + consider_guard_nonnull = _consider_guard_cc + consider_guard_isnull = _consider_guard_cc def consider_finish(self, op): # the frame is in ebp, but we have to point where in the frame is @@ -415,6 +418,7 @@ consider_guard_no_overflow = consider_guard_no_exception consider_guard_overflow = consider_guard_no_exception + consider_guard_not_forced = consider_guard_no_exception def consider_guard_value(self, op): x = self.make_sure_var_in_reg(op.getarg(0)) @@ -482,17 +486,9 @@ consider_int_or = _consider_binop_symm consider_int_xor = _consider_binop_symm - def _consider_binop_with_guard(self, op, guard_op): - loc, argloc = self._consider_binop_part(op) - self.perform_with_guard(op, guard_op, [loc, argloc], loc) - - def _consider_binop_with_guard_symm(self, op, guard_op): - loc, argloc = self._consider_binop_part(op, symm=True) - self.perform_with_guard(op, guard_op, [loc, argloc], loc) - - consider_int_mul_ovf = _consider_binop_with_guard_symm - consider_int_sub_ovf = _consider_binop_with_guard - consider_int_add_ovf = _consider_binop_with_guard_symm + consider_int_mul_ovf = _consider_binop_symm + consider_int_sub_ovf = _consider_binop + consider_int_add_ovf = _consider_binop_symm def consider_int_neg(self, op): res = self.rm.force_result_in_reg(op.result, op.getarg(0)) @@ -541,7 +537,7 @@ consider_uint_floordiv = consider_int_floordiv - def _consider_compop(self, op, guard_op): + def _consider_compop(self, op): vx = op.getarg(0) vy = op.getarg(1) arglocs = [self.loc(vx), self.loc(vy)] @@ -551,12 +547,9 @@ pass else: arglocs[0] = self.rm.make_sure_var_in_reg(vx) - if guard_op is None: - loc = self.rm.force_allocate_reg(op.result, args, - need_lower_byte=True) - self.perform(op, arglocs, loc) - else: - self.perform_with_guard(op, guard_op, arglocs, None) + self.possibly_free_vars(args) + loc = self.force_allocate_reg_or_cc(op.result) + self.perform(op, arglocs, loc) consider_int_lt = _consider_compop consider_int_gt = _consider_compop @@ -582,7 +575,7 @@ consider_float_mul = _consider_float_op # xxx could be _symm consider_float_truediv = _consider_float_op - def _consider_float_cmp(self, op, guard_op): + def _consider_float_cmp(self, op): vx = op.getarg(0) vy = op.getarg(1) arglocs = [self.loc(vx), self.loc(vy)] @@ -592,11 +585,9 @@ arglocs[1] = self.xrm.make_sure_var_in_reg(vy) else: arglocs[0] = self.xrm.make_sure_var_in_reg(vx) - if guard_op is None: - res = self.rm.force_allocate_reg(op.result, need_lower_byte=True) - self.perform(op, arglocs, res) - else: - self.perform_with_guard(op, guard_op, arglocs, None) + self.possibly_free_vars(op.getarglist()) + loc = self.force_allocate_reg_or_cc(op.result) + self.perform(op, arglocs, loc) consider_float_lt = _consider_float_cmp consider_float_le = _consider_float_cmp @@ -737,7 +728,7 @@ else: self._consider_call(op) - def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None): + def _call(self, op, arglocs, force_store=[], guard_not_forced=False): # we need to save registers on the stack: # # - at least the non-callee-saved registers @@ -750,7 +741,7 @@ # grab_frame_values() would not be able to locate values in # callee-saved registers. # - save_all_regs = guard_not_forced_op is not None + save_all_regs = guard_not_forced self.xrm.before_call(force_store, save_all_regs=save_all_regs) if not save_all_regs: gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap @@ -768,12 +759,9 @@ resloc = self.rm.after_call(op.result) else: resloc = None - if guard_not_forced_op is not None: - self.perform_with_guard(op, guard_not_forced_op, arglocs, resloc) - else: - self.perform(op, arglocs, resloc) + self.perform(op, arglocs, resloc) - def _consider_call(self, op, guard_not_forced_op=None, first_arg_index=1): From noreply at buildbot.pypy.org Sat Sep 5 11:14:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 11:14:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: add dump() on exported state Message-ID: <20150905091453.C34791C0170@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79451:e2cc2266dc5a Date: 2015-09-05 11:14 +0200 http://bitbucket.org/pypy/pypy/changeset/e2cc2266dc5a/ Log: add dump() on exported state diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -74,6 +74,10 @@ opinfo.setitem(self.getfield_op.getdescr(), index, self.res, pop, cf, optheap=optheap) + def repr(self, memo): + return "HeapOp(%s, %s)" % (self.res.repr(memo), + self.getfield_op.repr(memo)) + def add_op_to_short(self, sb): sop = self.getfield_op preamble_arg = sb.produce_arg(sop.getarg(0)) @@ -125,6 +129,9 @@ opnum = op.getopnum() return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist)) + def repr(self, memo): + return "PureOp(%s)" % (self.res.repr(memo),) + def __repr__(self): return "PureOp(%r)" % (self.res,) @@ -152,6 +159,9 @@ opnum = OpHelpers.call_loopinvariant_for_descr(op.getdescr()) return ProducedShortOp(self, op.copy_and_change(opnum, args=arglist)) + def repr(self, memo): + return "LoopInvariantOp(%s)" % (self.res.repr(memo),) + def __repr__(self): return "LoopInvariantOp(%r)" % (self.res,) @@ -174,6 +184,11 @@ l.append(pop) return l + def repr(self, memo): + return "CompoundOp(%s, %s, %s)" % (self.res.repr(memo), + self.one.repr(memo), + self.two.repr(memo)) + class AbstractProducedShortOp(object): pass @@ -188,6 +203,9 @@ self.short_op.produce_op(opt, self.preamble_op, exported_infos, invented_name=self.invented_name) + def repr(self, memo): + return self.short_op.repr(memo) + def __repr__(self): return "%r -> %r" % (self.short_op, self.preamble_op) @@ -205,6 +223,9 @@ def produce_op(self, opt, preamble_op, exported_infos, invented_name): assert not invented_name + def repr(self, memo): + return "INP(%s)" % (self.res.repr(memo),) + def __repr__(self): return "INP(%r -> %r)" % (self.res, self.preamble_op) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -12,7 +12,7 @@ VirtualStateConstructor, VirtualStatesCantMatch) from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp from rpython.jit.metainterp import compile -from rpython.rlib.debug import debug_print +from rpython.rlib.debug import debug_print, debug_start, debug_stop class UnrollableOptimizer(Optimizer): def force_op_from_preamble(self, preamble_op): @@ -455,6 +455,15 @@ self.short_boxes = short_boxes self.renamed_inputargs = renamed_inputargs self.short_inputargs = short_inputargs + self.dump() + + def dump(self): + debug_start("jit-log-exported-state") + memo = {} + debug_print("[" + ", ".join([x.repr_short(memo) for x in self.next_iteration_args]) + "]") + for box in self.short_boxes: + debug_print(" " + box.repr(memo)) + debug_stop("jit-log-exported-state") def final(self): return False From noreply at buildbot.pypy.org Sat Sep 5 11:19:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 11:19:08 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: log short preamble too Message-ID: <20150905091908.4CF901C0170@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79452:e17d7cbefde1 Date: 2015-09-05 11:19 +0200 http://bitbucket.org/pypy/pypy/changeset/e17d7cbefde1/ Log: log short preamble too diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -303,6 +303,11 @@ original_jitcell_token=jitcell_token) start_label = ResOperation(rop.LABEL, start_state.renamed_inputargs, descr=start_descr) + label_token = loop_info.label_op.getdescr() + assert isinstance(label_token, TargetToken) + if label_token.short_preamble: + metainterp_sd.logger_ops.log_short_preamble([], + label_token.short_preamble) loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as + [loop_info.label_op] + loop_ops) if not we_are_translated(): @@ -354,6 +359,11 @@ except InvalidLoop: return None + label_token = loop_info.label_op.getdescr() + assert isinstance(label_token, TargetToken) + if label_token.short_preamble: + metainterp_sd.logger_ops.log_short_preamble([], + label_token.short_preamble) loop = partial_trace loop.original_jitcell_token = loop_jitcell_token loop.operations = (loop.operations + loop_info.extra_same_as + From noreply at buildbot.pypy.org Sat Sep 5 12:27:23 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 12:27:23 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: improve on having consistent names of boxes in translated version Message-ID: <20150905102723.CCA5F1C146A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79453:9cb5d0626cce Date: 2015-09-05 12:27 +0200 http://bitbucket.org/pypy/pypy/changeset/9cb5d0626cce/ Log: improve on having consistent names of boxes in translated version diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -24,6 +24,8 @@ raise SwitchToBlackhole(Counters.ABORT_BRIDGE) class CompileData(object): + memo = None + def forget_optimization_info(self): for arg in self.start_label.getarglist(): arg.set_forwarded(None) @@ -54,7 +56,8 @@ opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.optimize_preamble(self.start_label, self.end_label, self.operations, - self.call_pure_results) + self.call_pure_results, + self.box_names_memo) else: opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.propagate_all_forward(self.start_label.getarglist(), @@ -97,7 +100,8 @@ opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.optimize_bridge(self.start_label, self.operations, self.call_pure_results, - self.inline_short_preamble) + self.inline_short_preamble, + self.box_names_memo) class UnrolledLoopData(CompileData): """ This represents label() ops jump with extra info that's from the @@ -217,7 +221,7 @@ enable_opts=enable_opts) try: loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd, - data) + metainterp.box_names_memo, data) except InvalidLoop: return None loop = create_empty_loop(metainterp) @@ -235,7 +239,7 @@ loop.check_consistency() jitcell_token.target_tokens = [target_token] send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", - inputargs) + inputargs, metainterp.box_names_memo) record_loop_or_bridge(metainterp_sd, loop) return target_token @@ -271,6 +275,7 @@ enable_opts=enable_opts) try: start_state, preamble_ops = optimize_trace(metainterp_sd, jitdriver_sd, + metainterp.box_names_memo, preamble_data) except InvalidLoop: return None @@ -285,6 +290,7 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, + metainterp.box_names_memo, loop_data) except InvalidLoop: return None @@ -307,14 +313,14 @@ assert isinstance(label_token, TargetToken) if label_token.short_preamble: metainterp_sd.logger_ops.log_short_preamble([], - label_token.short_preamble) + label_token.short_preamble, metainterp.box_names_memo) loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as + [loop_info.label_op] + loop_ops) if not we_are_translated(): loop.check_consistency() jitcell_token.target_tokens = [start_descr] + jitcell_token.target_tokens send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", - inputargs) + inputargs, metainterp.box_names_memo) record_loop_or_bridge(metainterp_sd, loop) return start_descr @@ -345,6 +351,7 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, + metainterp.box_names_memo, loop_data) except InvalidLoop: # Fall back on jumping directly to preamble @@ -355,6 +362,7 @@ inline_short_preamble=False) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, + metainterp.box_names_memo, loop_data) except InvalidLoop: return None @@ -363,7 +371,7 @@ assert isinstance(label_token, TargetToken) if label_token.short_preamble: metainterp_sd.logger_ops.log_short_preamble([], - label_token.short_preamble) + label_token.short_preamble, metainterp.box_names_memo) loop = partial_trace loop.original_jitcell_token = loop_jitcell_token loop.operations = (loop.operations + loop_info.extra_same_as + @@ -460,9 +468,9 @@ def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations, - looptoken, log=True, name=''): + looptoken, log=True, name='', memo=None): metainterp_sd.logger_ops.log_loop(inputargs, operations, -2, - 'compiling', name=name) + 'compiling', name=name, memo=memo) return metainterp_sd.cpu.compile_loop(inputargs, operations, looptoken, jd_id=jd_id, unique_id=unique_id, @@ -470,8 +478,9 @@ logger=metainterp_sd.logger_ops) def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, - original_loop_token, log=True): - metainterp_sd.logger_ops.log_bridge(inputargs, operations, "compiling") + original_loop_token, log=True, memo=None): + metainterp_sd.logger_ops.log_bridge(inputargs, operations, "compiling", + memo=memo) assert isinstance(faildescr, AbstractFailDescr) return metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations, original_loop_token, log=log, @@ -486,7 +495,7 @@ item.reset_value() def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type, - orig_inpargs): + orig_inpargs, memo): forget_optimization_info(loop.operations) forget_optimization_info(loop.inputargs) vinfo = jitdriver_sd.virtualizable_info @@ -521,7 +530,8 @@ asminfo = do_compile_loop(jitdriver_sd.index, unique_id, metainterp_sd, loop.inputargs, operations, original_jitcell_token, - name=loopname) + name=loopname, + memo=memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -545,7 +555,7 @@ metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token) def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs, - operations, original_loop_token): + operations, original_loop_token, memo): forget_optimization_info(operations) forget_optimization_info(inputargs) if not we_are_translated(): @@ -567,7 +577,7 @@ try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, - original_loop_token) + original_loop_token, memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() @@ -583,7 +593,7 @@ else: ops_offset = None metainterp_sd.logger_ops.log_bridge(inputargs, operations, None, faildescr, - ops_offset) + ops_offset, memo=memo) # #if metainterp_sd.warmrunnerdesc is not None: # for tests # metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive( @@ -801,7 +811,8 @@ propagate_original_jitcell_token(new_loop) send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata, self, inputargs, new_loop.operations, - new_loop.original_jitcell_token) + new_loop.original_jitcell_token, + metainterp.box_names_memo) def make_a_counter_per_value(self, guard_value_op): assert guard_value_op.getopnum() == rop.GUARD_VALUE @@ -991,7 +1002,7 @@ propagate_original_jitcell_token(new_loop) send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd, metainterp_sd, new_loop, "entry bridge", - orig_inputargs) + orig_inputargs, metainterp.box_names_memo) # send the new_loop to warmspot.py, to be called directly the next time jitdriver_sd.warmstate.attach_procedure_to_interp( self.original_greenkey, jitcell_token) @@ -1035,7 +1046,8 @@ call_pure_results=call_pure_results, enable_opts=enable_opts) try: - info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data) + info, newops = optimize_trace(metainterp_sd, jitdriver_sd, + metainterp.box_names_memo, data) except InvalidLoop: debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -12,90 +12,103 @@ self.metainterp_sd = metainterp_sd self.guard_number = guard_number - def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None, name=''): + def log_loop(self, inputargs, operations, number=0, type=None, + ops_offset=None, name='', memo=None): if type is None: debug_start("jit-log-noopt-loop") debug_print("# Loop", number, '(%s)' % name, ":", "noopt", "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-noopt-loop") elif type == "rewritten": debug_start("jit-log-rewritten-loop") debug_print("# Loop", number, '(%s)' % name, ":", type, "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-rewritten-loop") elif number == -2: debug_start("jit-log-compiling-loop") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-compiling-loop") else: debug_start("jit-log-opt-loop") debug_print("# Loop", number, '(%s)' % name, ":", type, "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-opt-loop") return logops def log_bridge(self, inputargs, operations, extra=None, - descr=None, ops_offset=None): + descr=None, ops_offset=None, memo=None): if extra == "noopt": debug_start("jit-log-noopt-bridge") debug_print("# bridge out of Guard", "0x%x" % compute_unique_id(descr), "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-noopt-bridge") elif extra == "rewritten": debug_start("jit-log-rewritten-bridge") debug_print("# bridge out of Guard", "0x%x" % compute_unique_id(descr), "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-rewritten-bridge") elif extra == "compiling": debug_start("jit-log-compiling-bridge") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-compiling-bridge") else: debug_start("jit-log-opt-bridge") debug_print("# bridge out of Guard", "0x%x" % r_uint(compute_unique_id(descr)), "with", len(operations), "ops") - logops = self._log_operations(inputargs, operations, ops_offset) + logops = self._log_operations(inputargs, operations, ops_offset, + memo) debug_stop("jit-log-opt-bridge") return logops - def log_short_preamble(self, inputargs, operations): + def log_short_preamble(self, inputargs, operations, memo=None): debug_start("jit-log-short-preamble") - logops = self._log_operations(inputargs, operations, ops_offset=None) + logops = self._log_operations(inputargs, operations, ops_offset=None, + memo=memo) debug_stop("jit-log-short-preamble") return logops - def _log_operations(self, inputargs, operations, ops_offset): + def _log_operations(self, inputargs, operations, ops_offset, memo=None): if not have_debug_prints(): return None - logops = self._make_log_operations() - logops._log_operations(inputargs, operations, ops_offset) + logops = self._make_log_operations(memo) + logops._log_operations(inputargs, operations, ops_offset, memo) return logops - def _make_log_operations(self): - return LogOperations(self.metainterp_sd, self.guard_number) + def _make_log_operations(self, memo): + return LogOperations(self.metainterp_sd, self.guard_number, memo) def repr_of_resop(self, op): - return LogOperations(self.metainterp_sd, self.guard_number).repr_of_resop(op) + # XXX fish the memo from somewhere + return LogOperations(self.metainterp_sd, self.guard_number, + None).repr_of_resop(op) class LogOperations(object): """ - ResOperation logger. Each instance contains a memo giving numbers - to boxes, and is typically used to log a single loop. + ResOperation logger. """ - def __init__(self, metainterp_sd, guard_number): + def __init__(self, metainterp_sd, guard_number, memo): self.metainterp_sd = metainterp_sd self.ts = metainterp_sd.cpu.ts self.guard_number = guard_number - self.memo = {} + if memo is None: + memo = {} + self.memo = memo def repr_of_descr(self, descr): return descr.repr_of_descr() @@ -180,7 +193,8 @@ return s_offset + res + op.getopname() + '(' + args + ')' + fail_args - def _log_operations(self, inputargs, operations, ops_offset=None): + def _log_operations(self, inputargs, operations, ops_offset=None, + memo=None): if not have_debug_prints(): return if ops_offset is None: @@ -197,8 +211,8 @@ offset = ops_offset[None] debug_print("+%d: --end of the loop--" % offset) - def log_loop(self, loop): - self._log_operations(loop.inputargs, loop.operations) + def log_loop(self, loop, memo=None): + self._log_operations(loop.inputargs, loop.operations, memo=memo) def int_could_be_an_address(x): if we_are_translated(): 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 @@ -46,14 +46,16 @@ return optimizations, unroll -def optimize_trace(metainterp_sd, jitdriver_sd, compile_data): +def optimize_trace(metainterp_sd, jitdriver_sd, memo, compile_data): """Optimize loop.operations to remove internal overheadish operations. """ debug_start("jit-optimize") inputargs = compile_data.start_label.getarglist() try: metainterp_sd.logger_noopt.log_loop(inputargs, - compile_data.operations) + compile_data.operations, + memo) + compile_data.box_names_memo = memo optimizations, unroll = build_opt_chain(metainterp_sd, compile_data.enable_opts) return compile_data.optimize(metainterp_sd, jitdriver_sd, 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 @@ -239,7 +239,6 @@ self.metainterp_sd = metainterp_sd self.jitdriver_sd = jitdriver_sd self.cpu = metainterp_sd.cpu - self.logops = LogOperations(metainterp_sd, False) self.interned_refs = self.cpu.ts.new_ref_dict() self.interned_ints = {} self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -108,13 +108,14 @@ if check_newops: assert not self.optimizer._newoperations - def optimize_preamble(self, start_label, end_label, ops, call_pure_results): + def optimize_preamble(self, start_label, end_label, ops, call_pure_results, + memo): self._check_no_forwarding([[start_label, end_label], ops]) info, newops = self.optimizer.propagate_all_forward( start_label.getarglist()[:], ops, call_pure_results, True, flush=False) exported_state = self.export_state(start_label, end_label.getarglist(), - info.inputargs) + info.inputargs, memo) exported_state.quasi_immutable_deps = info.quasi_immutable_deps # we need to absolutely make sure that we've cleaned up all # the optimization info @@ -209,7 +210,7 @@ return label_vs def optimize_bridge(self, start_label, operations, call_pure_results, - inline_short_preamble): + inline_short_preamble, box_names_memo): self._check_no_forwarding([start_label.getarglist(), operations]) info, ops = self.optimizer.propagate_all_forward( @@ -241,7 +242,7 @@ return self.jump_to_preamble(cell_token, jump_op, info) exported_state = self.export_state(start_label, operations[-1].getarglist(), - info.inputargs) + info.inputargs, box_names_memo) exported_state.quasi_immutable_deps = self.optimizer.quasi_immutable_deps self.optimizer._clean_optimization_info(self.optimizer._newoperations) return exported_state, self.optimizer._newoperations @@ -345,7 +346,8 @@ for op in short: op.set_forwarded(None) - def export_state(self, start_label, original_label_args, renamed_inputargs): + def export_state(self, start_label, original_label_args, renamed_inputargs, + memo): end_args = [self.optimizer.force_box_for_end_of_preamble(a) for a in original_label_args] self.optimizer.flush() @@ -370,7 +372,7 @@ self.optimizer._clean_optimization_info(start_label.getarglist()) return ExportedState(label_args, end_args, virtual_state, infos, short_boxes, renamed_inputargs, - short_inputargs) + short_inputargs, memo) def import_state(self, targetop, exported_state): # the mapping between input args (from old label) and what we need @@ -447,7 +449,7 @@ def __init__(self, end_args, next_iteration_args, virtual_state, exported_infos, short_boxes, renamed_inputargs, - short_inputargs): + short_inputargs, memo): self.end_args = end_args self.next_iteration_args = next_iteration_args self.virtual_state = virtual_state @@ -455,11 +457,10 @@ self.short_boxes = short_boxes self.renamed_inputargs = renamed_inputargs self.short_inputargs = short_inputargs - self.dump() + self.dump(memo) - def dump(self): + def dump(self, memo): debug_start("jit-log-exported-state") - memo = {} debug_print("[" + ", ".join([x.repr_short(memo) for x in self.next_iteration_args]) + "]") for box in self.short_boxes: debug_print(" " + box.repr(memo)) 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 @@ -1884,6 +1884,8 @@ self.call_ids = [] self.current_call_id = 0 + self.box_names_memo = {} + def retrace_needed(self, trace, exported_state): self.partial_trace = trace self.retracing_from = len(self.history.operations) - 1 @@ -2206,11 +2208,11 @@ else: greenkey = self.current_merge_points[0][0][:jd_sd.num_green_args] self.staticdata.warmrunnerdesc.hooks.on_abort(reason, - jd_sd.jitdriver, - greenkey, - jd_sd.warmstate.get_location_str(greenkey), - self.staticdata.logger_ops._make_log_operations(), - self.history.operations) + jd_sd.jitdriver, greenkey, + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations( + self.box_names_memo), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): From noreply at buildbot.pypy.org Sat Sep 5 12:33:35 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 12:33:35 +0200 (CEST) Subject: [pypy-commit] pypy conditional_call_value: in-progress: tweak the user API Message-ID: <20150905103335.E565A1C146A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: conditional_call_value Changeset: r79454:f010addba075 Date: 2015-09-05 12:33 +0200 http://bitbucket.org/pypy/pypy/changeset/f010addba075/ Log: in-progress: tweak the user API diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -1106,67 +1106,64 @@ return hop.genop('jit_record_known_class', [v_inst, v_cls], resulttype=lltype.Void) -def _jit_conditional_call(condition, function, *args): - pass - at specialize.call_location() -def conditional_call(condition, function, *args): +def conditional_call(condition, function, *args, **kwds): + default = kwds.pop('default', None) + assert not kwds + if condition: + return function(*args) + return default + +def _ll_cond_call(condition, ll_default, ll_function, *ll_args): if we_are_jitted(): - _jit_conditional_call(condition, function, *args) + from rpython.rtyper.lltypesystem import lltype + from rpython.rtyper.lltypesystem.lloperation import llop + RESTYPE = lltype.typeOf(ll_default) + return llop.jit_conditional_call(RESTYPE, condition, ll_default, + ll_function, *ll_args) else: if condition: - return function(*args) -conditional_call._always_inline_ = True + return ll_function(*ll_args) + return ll_default +_ll_cond_call._always_inline_ = True class ConditionalCallEntry(ExtRegistryEntry): - _about_ = _jit_conditional_call + _about_ = conditional_call - def compute_result_annotation(self, *args_s): - self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key, - args_s[1], args_s[2:]) + def compute_result_annotation(self, *args_s, **kwds_s): + from rpython.annotator import model as annmodel - def specialize_call(self, hop): + s_res = self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key, + args_s[1], args_s[2:]) + if 's_default' in kwds_s: + assert kwds_s.keys() == ['s_default'] + return annmodel.unionof(s_res, kwds_s['s_default']) + else: + assert not kwds_s + return None + + def specialize_call(self, hop, i_default=None): from rpython.rtyper.lltypesystem import lltype - args_v = hop.inputargs(lltype.Bool, lltype.Void, *hop.args_r[2:]) + end = len(hop.args_r) - (i_default is not None) + inputargs = [lltype.Bool, lltype.Void] + hop.args_r[2:end] + if i_default is not None: + assert i_default == end + inputargs.append(hop.r_result) + + args_v = hop.inputargs(*inputargs) args_v[1] = hop.args_r[1].get_concrete_llfn(hop.args_s[1], - hop.args_s[2:], hop.spaceop) + hop.args_s[2:end], + hop.spaceop) + if i_default is not None: + v_default = args_v.pop() + else: + v_default = hop.inputconst(lltype.Void, None) + args_v.insert(1, v_default) + hop.exception_is_here() - return hop.genop('jit_conditional_call', args_v) + return hop.gendirectcall(_ll_cond_call, *args_v) -def _jit_conditional_call_value(condition, function, default_value, *args): - return default_value - - at specialize.call_location() -def conditional_call_value(condition, function, default_value, *args): - if we_are_jitted(): - return _jit_conditional_call_value(condition, function, default_value, - *args) - else: - if condition: - return function(*args) - return default_value -conditional_call._always_inline_ = True - -class ConditionalCallValueEntry(ExtRegistryEntry): - _about_ = _jit_conditional_call_value - - def compute_result_annotation(self, *args_s): - s_result = self.bookkeeper.emulate_pbc_call( - self.bookkeeper.position_key, args_s[1], args_s[3:], - callback = self.bookkeeper.position_key) - return s_result - - def specialize_call(self, hop): - from rpython.rtyper.lltypesystem import lltype - - args_v = hop.inputargs(lltype.Bool, lltype.Void, *hop.args_r[2:]) - args_v[1] = hop.args_r[1].get_concrete_llfn(hop.args_s[1], - hop.args_s[3:], hop.spaceop) - hop.exception_is_here() - resulttype = hop.r_result - return hop.genop('jit_conditional_call_value', args_v, - resulttype=resulttype) class Counters(object): counters=""" diff --git a/rpython/rlib/test/test_jit.py b/rpython/rlib/test/test_jit.py --- a/rpython/rlib/test/test_jit.py +++ b/rpython/rlib/test/test_jit.py @@ -300,3 +300,38 @@ mix = MixLevelHelperAnnotator(t.rtyper) mix.getgraph(later, [annmodel.s_Bool], annmodel.s_None) mix.finish() + + def test_conditional_call_value(self): + def g(m): + return m + 42 + def f(n, m): + return conditional_call(n >= 0, g, m, default=678) + + res = self.interpret(f, [10, 20]) + assert res == 20 + 42 + res = self.interpret(f, [-10, 20]) + assert res == 678 + + def test_conditional_call_void(self): + class X: + pass + glob = X() + # + def g(m): + glob.x += m + # + def h(): + glob.x += 2 + # + def f(n, m): + glob.x = 0 + conditional_call(n >= 0, g, m) + conditional_call(n >= 5, h) + return glob.x + + res = self.interpret(f, [10, 20]) + assert res == 22 + res = self.interpret(f, [2, 20]) + assert res == 20 + res = self.interpret(f, [-2, 20]) + assert res == 0 diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -548,9 +548,6 @@ def op_jit_conditional_call(self, *args): raise NotImplementedError("should not be called while not jitted") - def op_jit_conditional_call_value(self, *args): - raise NotImplementedError("should not be called while not jitted") - def op_get_exception_addr(self, *args): raise NotImplementedError 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 @@ -451,8 +451,7 @@ 'jit_force_quasi_immutable': LLOp(canrun=True), 'jit_record_known_class' : LLOp(canrun=True), 'jit_ffi_save_result': LLOp(canrun=True), - 'jit_conditional_call': LLOp(), - 'jit_conditional_call_value': LLOp(), + 'jit_conditional_call': LLOp(), 'get_exception_addr': LLOp(), 'get_exc_value_addr': LLOp(), 'do_malloc_fixedsize':LLOp(canmallocgc=True), diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py --- a/rpython/rtyper/lltypesystem/rstr.py +++ b/rpython/rtyper/lltypesystem/rstr.py @@ -374,7 +374,8 @@ if not s: return 0 x = s.hash - return jit.conditional_call_value(x == 0, LLHelpers._ll_strhash, x, s) + return jit.conditional_call(x == 0, LLHelpers._ll_strhash, s, + default=x) @staticmethod def ll_length(s): From noreply at buildbot.pypy.org Sat Sep 5 12:37:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 12:37:08 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: simplify the usage of memo Message-ID: <20150905103708.512711C146A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79455:b254ccaf6527 Date: 2015-09-05 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/b254ccaf6527/ Log: simplify the usage of memo diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -158,11 +158,11 @@ # RPython-friendly version if self.type != 'v': try: - sres = '%s = ' % memo[self] + num = memo[self] except KeyError: - name = self.type + str(len(memo)) - memo[self] = name - sres = name + ' = ' + num = len(memo) + memo[self] = num + sres = self.type + str(num) + ' = ' #if self.result is not None: # sres = '%s = ' % (self.result,) else: @@ -185,11 +185,11 @@ def repr_short(self, memo): try: - return memo[self] + num = memo[self] except KeyError: - name = self.type + str(len(memo)) - memo[self] = name - return name + num = len(memo) + memo[self] = num + return self.type + str(num) def __repr__(self): r = self.repr(self._repr_memo) @@ -458,11 +458,11 @@ def repr(self, memo): try: - return memo[self] + num = memo[self] except KeyError: - name = self.type + str(len(memo)) - memo[self] = name - return name + num = len(memo) + memo[self] = num + return self.type + str(num) def __repr__(self): return self.repr(self._repr_memo) From noreply at buildbot.pypy.org Sat Sep 5 12:50:02 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 12:50:02 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fight with annotation Message-ID: <20150905105002.8594A1C0170@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79456:81ad88375b22 Date: 2015-09-05 12:50 +0200 http://bitbucket.org/pypy/pypy/changeset/81ad88375b22/ Log: fight with annotation diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -221,7 +221,7 @@ enable_opts=enable_opts) try: loop_info, ops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, data) + data, metainterp.box_names_memo) except InvalidLoop: return None loop = create_empty_loop(metainterp) @@ -275,8 +275,8 @@ enable_opts=enable_opts) try: start_state, preamble_ops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, - preamble_data) + preamble_data, + metainterp.box_names_memo) except InvalidLoop: return None @@ -290,8 +290,8 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, - loop_data) + loop_data, + metainterp.box_names_memo) except InvalidLoop: return None @@ -351,8 +351,8 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, - loop_data) + loop_data, + metainterp.box_names_memo) except InvalidLoop: # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token) @@ -362,8 +362,8 @@ inline_short_preamble=False) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, - loop_data) + loop_data, + metainterp.box_names_memo) except InvalidLoop: return None @@ -469,8 +469,8 @@ def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations, looptoken, log=True, name='', memo=None): - metainterp_sd.logger_ops.log_loop(inputargs, operations, -2, - 'compiling', name=name, memo=memo) + metainterp_sd.logger_ops.log_loop(inputargs, operations, number=-2, + type='compiling', name=name, memo=memo) return metainterp_sd.cpu.compile_loop(inputargs, operations, looptoken, jd_id=jd_id, unique_id=unique_id, @@ -1047,7 +1047,7 @@ enable_opts=enable_opts) try: info, newops = optimize_trace(metainterp_sd, jitdriver_sd, - metainterp.box_names_memo, data) + data, metainterp.box_names_memo) except InvalidLoop: debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise 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 @@ -46,7 +46,7 @@ return optimizations, unroll -def optimize_trace(metainterp_sd, jitdriver_sd, memo, compile_data): +def optimize_trace(metainterp_sd, jitdriver_sd, compile_data, memo=None): """Optimize loop.operations to remove internal overheadish operations. """ debug_start("jit-optimize") @@ -55,6 +55,8 @@ metainterp_sd.logger_noopt.log_loop(inputargs, compile_data.operations, memo) + if memo is None: + memo = {} compile_data.box_names_memo = memo optimizations, unroll = build_opt_chain(metainterp_sd, compile_data.enable_opts) From noreply at buildbot.pypy.org Sat Sep 5 12:58:19 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 12:58:19 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: hack differently Message-ID: <20150905105819.CC4C21C0362@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79457:dff81b8e230a Date: 2015-09-05 12:58 +0200 http://bitbucket.org/pypy/pypy/changeset/dff81b8e230a/ Log: hack differently diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -469,8 +469,8 @@ def do_compile_loop(jd_id, unique_id, metainterp_sd, inputargs, operations, looptoken, log=True, name='', memo=None): - metainterp_sd.logger_ops.log_loop(inputargs, operations, number=-2, - type='compiling', name=name, memo=memo) + metainterp_sd.logger_ops.log_loop(inputargs, operations, -2, + 'compiling', None, name, memo) return metainterp_sd.cpu.compile_loop(inputargs, operations, looptoken, jd_id=jd_id, unique_id=unique_id, 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 @@ -2767,7 +2767,7 @@ return i # seen = [] - def my_optimize_trace(metainterp_sd, jitdriver_sd, data): + def my_optimize_trace(metainterp_sd, jitdriver_sd, data, memo=None): seen.append('unroll' in data.enable_opts) raise InvalidLoop old_optimize_trace = optimizeopt.optimize_trace diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py --- a/rpython/jit/metainterp/test/test_compile.py +++ b/rpython/jit/metainterp/test/test_compile.py @@ -26,7 +26,7 @@ self.seen.append((inputargs, operations, token)) class FakeLogger(object): - def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None, name=''): + def log_loop(self, inputargs, operations, number=0, type=None, ops_offset=None, name='', memo=None): pass def repr_of_resop(self, op): @@ -62,6 +62,7 @@ class FakeMetaInterp: call_pure_results = {} + box_names_memo = {} class jitdriver_sd: index = 0 warmstate = FakeState() diff --git a/rpython/jit/metainterp/test/test_logger.py b/rpython/jit/metainterp/test/test_logger.py --- a/rpython/jit/metainterp/test/test_logger.py +++ b/rpython/jit/metainterp/test/test_logger.py @@ -38,14 +38,14 @@ loop.inputargs, loop.operations, ops_offset=ops_offset, name=name) - def _make_log_operations(self1): + def _make_log_operations(self1, memo): class LogOperations(logger.LogOperations): def repr_of_descr(self, descr): for k, v in self1.namespace.items(): if v == descr: return k return descr.repr_of_descr() - logops = LogOperations(self1.metainterp_sd, self1.guard_number) + logops = LogOperations(self1.metainterp_sd, self1.guard_number, memo) self1.logops = logops return logops From noreply at buildbot.pypy.org Sat Sep 5 13:01:04 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 13:01:04 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix Message-ID: <20150905110104.CCC281C132A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79458:81100d90b796 Date: 2015-09-05 13:01 +0200 http://bitbucket.org/pypy/pypy/changeset/81100d90b796/ Log: fix 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 @@ -54,7 +54,7 @@ try: metainterp_sd.logger_noopt.log_loop(inputargs, compile_data.operations, - memo) + memo=memo) if memo is None: memo = {} compile_data.box_names_memo = memo From noreply at buildbot.pypy.org Sat Sep 5 13:13:37 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 13:13:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Trying out a variant that makes the branch 'conditional_call_value' Message-ID: <20150905111337.E26DE1C1358@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79459:75a00a3b038f Date: 2015-09-05 12:52 +0200 http://bitbucket.org/pypy/pypy/changeset/75a00a3b038f/ Log: Trying out a variant that makes the branch 'conditional_call_value' mostly unneeded (it should jit to two reads of 's.hash', instead of only one in that branch) diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py --- a/rpython/rtyper/lltypesystem/rstr.py +++ b/rpython/rtyper/lltypesystem/rstr.py @@ -358,20 +358,21 @@ return b @staticmethod - @jit.elidable - def ll_strhash(s): + def _compute_hash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the # special non-computed-yet value. + x = _hash_string(s.chars) + if x == 0: + x = 29872897 + s.hash = x + + @staticmethod + def ll_strhash(s): if not s: return 0 - x = s.hash - if x == 0: - x = _hash_string(s.chars) - if x == 0: - x = 29872897 - s.hash = x - return x + jit.conditional_call(s.hash == 0, LLHelpers._compute_hash, s) + return s.hash @staticmethod def ll_length(s): From noreply at buildbot.pypy.org Sat Sep 5 13:13:39 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 13:13:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix for rare annotation issue Message-ID: <20150905111339.EA63F1C1358@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79460:77d8c602142b Date: 2015-09-05 13:13 +0200 http://bitbucket.org/pypy/pypy/changeset/77d8c602142b/ Log: Test and fix for rare annotation issue diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -4492,6 +4492,15 @@ with py.test.raises(annmodel.AnnotatorError): a.build_types(f, [int]) + def test_dict_can_be_none_ordering_issue(self): + def g(d): + return 42 in d + def f(n): + g(None) + g({}) + a = self.RPythonAnnotator() + a.build_types(f, [int]) + def g(n): return [0, 1, 2, n] diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -49,6 +49,16 @@ return s_Bool contains_SomeObject.can_only_throw = [] + at op.contains.register(SomeNone) +def contains_SomeNone(annotator, obj, element): + # return False here for the case "... in None", because it can be later + # generalized to "... in d" where d is either None or the empty dict + # (which would also return the constant False) + s_bool = SomeBool() + s_bool.const = False + return s_bool +contains_SomeNone.can_only_throw = [] + @op.simple_call.register(SomeObject) def simple_call_SomeObject(annotator, func, *args): return annotator.annotation(func).call( From noreply at buildbot.pypy.org Sat Sep 5 14:09:58 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 14:09:58 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix tests Message-ID: <20150905120958.52DA51C0F15@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79461:018f1489cc93 Date: 2015-09-05 14:10 +0200 http://bitbucket.org/pypy/pypy/changeset/018f1489cc93/ Log: fix tests 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 @@ -396,7 +396,7 @@ class logger_noopt: @classmethod - def log_loop(*args): + def log_loop(*args, **kwds): pass class logger_ops: From noreply at buildbot.pypy.org Sat Sep 5 14:15:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 14:15:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: try to optimize resoperation Message-ID: <20150905121553.96D221C132A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79462:eb88042244ba Date: 2015-09-05 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/eb88042244ba/ Log: try to optimize resoperation diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -33,16 +33,17 @@ llop.debug_print(lltype.Void, "setting forwarded on:", self.__class__.__name__) raise SettingForwardedOnAbstractValue() + @specialize.arg(1) def get_box_replacement(op, not_const=False): - orig_op = op - c = 0 - while (op.get_forwarded() is not None and - not op.get_forwarded().is_info_class and - (not not_const or not op.get_forwarded().is_constant())): - c += 1 - op = op.get_forwarded() - if op is not orig_op and c > 1: - orig_op.set_forwarded(op) + # Read the chain "op, op._forwarded, op._forwarded._forwarded..." + # until we reach None or an Info instance, and return the last + # item before that. + while isinstance(op, AbstractResOpOrInputArg): # else, _forwarded is None + next_op = op._forwarded + if (next_op is None or next_op.is_info_class or + (not_const and next_op.is_constant())): + return op + op = next_op return op def reset_value(self): @@ -62,10 +63,18 @@ return op -class AbstractResOp(AbstractValue): +class AbstractResOpOrInputArg(AbstractValue): + _attrs_ = ('_forwarded',) + _forwarded = None # either another resop or OptInfo + + def get_forwarded(self): + return self._forwarded + + +class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" - _attrs_ = ('_forwarded',) + _attrs_ = () # debug name = "" @@ -75,7 +84,6 @@ type = 'v' boolreflex = -1 boolinverse = -1 - _forwarded = None # either another resop or OptInfo def getopnum(self): return self.opnum @@ -85,9 +93,6 @@ # return self is other or self.getarg(0).same_box(other) # return self is other - def get_forwarded(self): - return self._forwarded - def set_forwarded(self, forwarded_to): assert forwarded_to is not self self._forwarded = forwarded_to @@ -447,12 +452,7 @@ return history.ConstPtr(self.getref_base()) -class AbstractInputArg(AbstractValue): - _forwarded = None - - def get_forwarded(self): - return self._forwarded - +class AbstractInputArg(AbstractResOpOrInputArg): def set_forwarded(self, forwarded_to): self._forwarded = forwarded_to From noreply at buildbot.pypy.org Sat Sep 5 14:39:03 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 14:39:03 +0200 (CEST) Subject: [pypy-commit] pypy default: hg backout 75a00a3b038f: the jit explodes when seeing and optimizing Message-ID: <20150905123903.119061C0170@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79463:9291449ec424 Date: 2015-09-05 14:39 +0200 http://bitbucket.org/pypy/pypy/changeset/9291449ec424/ Log: hg backout 75a00a3b038f: the jit explodes when seeing and optimizing getfield_gc(p, 'hash') diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py --- a/rpython/rtyper/lltypesystem/rstr.py +++ b/rpython/rtyper/lltypesystem/rstr.py @@ -358,21 +358,20 @@ return b @staticmethod - def _compute_hash(s): + @jit.elidable + def ll_strhash(s): # unlike CPython, there is no reason to avoid to return -1 # but our malloc initializes the memory to zero, so we use zero as the # special non-computed-yet value. - x = _hash_string(s.chars) - if x == 0: - x = 29872897 - s.hash = x - - @staticmethod - def ll_strhash(s): if not s: return 0 - jit.conditional_call(s.hash == 0, LLHelpers._compute_hash, s) - return s.hash + x = s.hash + if x == 0: + x = _hash_string(s.chars) + if x == 0: + x = 29872897 + s.hash = x + return x @staticmethod def ll_length(s): From noreply at buildbot.pypy.org Sat Sep 5 14:54:42 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 5 Sep 2015 14:54:42 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: disable retrace_limit for now Message-ID: <20150905125442.450C21C0207@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79464:95dd372034f9 Date: 2015-09-05 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/95dd372034f9/ Log: disable retrace_limit for now diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -562,7 +562,7 @@ 'trace_limit': 6000, 'inlining': 1, 'loop_longevity': 1000, - 'retrace_limit': 5, + 'retrace_limit': 0, 'max_retrace_guards': 15, 'max_unroll_loops': 0, 'disable_unrolling': 200, From noreply at buildbot.pypy.org Sat Sep 5 15:40:22 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 5 Sep 2015 15:40:22 +0200 (CEST) Subject: [pypy-commit] pypy conditional_call_value: Check in these, which were meant for "default". The compute_hash() test Message-ID: <20150905134022.A15AE1C0207@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: conditional_call_value Changeset: r79465:9b7bcfa5c1e4 Date: 2015-09-05 15:40 +0200 http://bitbucket.org/pypy/pypy/changeset/9b7bcfa5c1e4/ Log: Check in these, which were meant for "default". The compute_hash() test relies on RPython seeing inside the ll_strhash() function, which is only true in this branch. diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -669,15 +669,20 @@ def optimize_GETFIELD_GC(self, op): value = self.getvalue(op.getarg(0)) + # The only interesting cases are if 'value' is an instance of + # AbstractVirtualStructValue. It might not be virtual even then, + # but we need to check first---otherwise we can crash on + # getfield_gc(some_string, 'hash'). + maybe_virtual = isinstance(value, AbstractVirtualStructValue) # If this is an immutable field (as indicated by op.is_always_pure()) # then it's safe to reuse the virtual's field, even if it has been # forced, because it should never be written to again. - if value.is_forced_virtual() and op.is_always_pure(): + if maybe_virtual and value.is_forced_virtual() and op.is_always_pure(): fieldvalue = value.getfield(op.getdescr(), None) if fieldvalue is not None: self.make_equal_to(op.result, fieldvalue) return - if value.is_virtual(): + if maybe_virtual and value.is_virtual(): assert isinstance(value, AbstractVirtualValue) fieldvalue = value.getfield(op.getdescr(), None) if fieldvalue is None: diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -958,3 +958,18 @@ self.meta_interp(f, []) self.check_simple_loop({"int_add": 1, "int_lt": 1, "guard_true": 1, 'jump': 1}) + + def test_string_hash_2(self): + from rpython.rlib.objectmodel import compute_hash + + jitdriver = JitDriver(greens=[], reds=['x', 'z', 'u']) + def f(x): + z = 0 + u = 0 + while z < 10: + jitdriver.jit_merge_point(x=x, z=z, u=u) + s = "abcdefghij"[:z] + u = compute_hash(s) + z += 1 + return u + self.meta_interp(f, [42]) From noreply at buildbot.pypy.org Sun Sep 6 09:56:59 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 09:56:59 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: ups you can't compare floats with == Message-ID: <20150906075659.801E41C11C8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79466:1e183beac86b Date: 2015-09-06 09:57 +0200 http://bitbucket.org/pypy/pypy/changeset/1e183beac86b/ Log: ups you can't compare floats with == 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 @@ -726,7 +726,10 @@ assert resvalue == upd.currfieldbox.getref_base() else: assert type == 'f' - assert resvalue == upd.currfieldbox.getfloatstorage() + # make the comparison more robust again NaNs + # see ConstFloat.same_constant + assert ConstFloat(resvalue).same_constant( + upd.currfieldbox.constbox()) return upd.currfieldbox resbox = self.execute_with_descr(opnum, fielddescr, box) upd.getfield_now_known(resbox) From noreply at buildbot.pypy.org Sun Sep 6 10:05:07 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 10:05:07 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: shuffle stuff around so we always have target_tokens[0] that points to preamble Message-ID: <20150906080507.8421E1C1DD9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79467:7a86aef00eb4 Date: 2015-09-06 10:05 +0200 http://bitbucket.org/pypy/pypy/changeset/7a86aef00eb4/ Log: shuffle stuff around so we always have target_tokens[0] that points to preamble diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -285,6 +285,9 @@ end_label = ResOperation(rop.LABEL, inputargs, descr=jitcell_token) jump_op = ResOperation(rop.JUMP, jumpargs, descr=jitcell_token) + start_descr = TargetToken(jitcell_token, + original_jitcell_token=jitcell_token) + jitcell_token.target_tokens = [start_descr] loop_data = UnrolledLoopData(end_label, jump_op, ops, start_state, call_pure_results=call_pure_results, enable_opts=enable_opts) @@ -305,8 +308,6 @@ quasi_immutable_deps.update(loop_info.quasi_immutable_deps) if quasi_immutable_deps: loop.quasi_immutable_deps = quasi_immutable_deps - start_descr = TargetToken(jitcell_token, - original_jitcell_token=jitcell_token) start_label = ResOperation(rop.LABEL, start_state.renamed_inputargs, descr=start_descr) label_token = loop_info.label_op.getdescr() @@ -318,7 +319,6 @@ [loop_info.label_op] + loop_ops) if not we_are_translated(): loop.check_consistency() - jitcell_token.target_tokens = [start_descr] + jitcell_token.target_tokens send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", inputargs, metainterp.box_names_memo) record_loop_or_bridge(metainterp_sd, loop) From noreply at buildbot.pypy.org Sun Sep 6 10:57:05 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 10:57:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Sort the vtable fields by decreasing size, like we do for the instance fields. Message-ID: <20150906085705.065471C12F1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79468:af9d90e513b9 Date: 2015-09-05 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/af9d90e513b9/ Log: Sort the vtable fields by decreasing size, like we do for the instance fields. diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py --- a/rpython/rtyper/rclass.py +++ b/rpython/rtyper/rclass.py @@ -251,9 +251,7 @@ allmethods = {} # class attributes llfields = [] - attrs = self.classdef.attrs.items() - attrs.sort() - for name, attrdef in attrs: + for name, attrdef in self.classdef.attrs.items(): if attrdef.readonly: s_value = attrdef.s_value s_unboundmethod = self.prepare_method(s_value) @@ -271,6 +269,8 @@ mangled_name = mangle('pbc%d' % counter, attr) pbcfields[access_set, attr] = mangled_name, r llfields.append((mangled_name, r.lowleveltype)) + llfields.sort() + llfields.sort(key=attr_reverse_size) # self.rbase = getclassrepr(self.rtyper, self.classdef.basedef) self.rbase.setup() @@ -492,19 +492,7 @@ fields[name] = mangled_name, r myllfields.append((mangled_name, r.lowleveltype)) - # Sort the instance attributes by decreasing "likely size", - # as reported by rffi.sizeof(), to minimize padding holes in C. - # Fields of the same size are sorted by name (by attrs.sort() - # above) just to minimize randomness. - def keysize((_, T)): - if T is lltype.Void: - return None - from rpython.rtyper.lltypesystem.rffi import sizeof - try: - return -sizeof(T) - except StandardError: - return None - myllfields.sort(key=keysize) + myllfields.sort(key=attr_reverse_size) if llfields is None: llfields = myllfields else: @@ -1072,6 +1060,19 @@ (lltype.typeOf(widest), name)) return default +def attr_reverse_size((_, T)): + # This is used to sort the instance or class attributes by decreasing + # "likely size", as reported by rffi.sizeof(), to minimize padding + # holes in C. Fields should first be sorted by name, just to minimize + # randomness, and then (stably) sorted by 'attr_reverse_size'. + if T is lltype.Void: + return None + from rpython.rtyper.lltypesystem.rffi import sizeof + try: + return -sizeof(T) + except StandardError: + return None + # ____________________________________________________________ # From noreply at buildbot.pypy.org Sun Sep 6 10:57:07 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 10:57:07 +0200 (CEST) Subject: [pypy-commit] pypy default: Wrong indentation! These tests were only half-run. Message-ID: <20150906085707.4E4B51C12F1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79469:b71b4486a66b Date: 2015-09-06 10:57 +0200 http://bitbucket.org/pypy/pypy/changeset/b71b4486a66b/ Log: Wrong indentation! These tests were only half-run. diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -1111,12 +1111,12 @@ r_box = self.alloc_string("!???????!") if r_box_is_const: r_box = r_box.constbox() - self.execute_operation(rop.COPYSTRCONTENT, - [s_box, r_box, - srcstart_box, - dststart_box, - length_box], 'void') - assert self.look_string(r_box) == "!??cdef?!" + self.execute_operation(rop.COPYSTRCONTENT, + [s_box, r_box, + srcstart_box, + dststart_box, + length_box], 'void') + assert self.look_string(r_box) == "!??cdef?!" def test_copyunicodecontent(self): s_box = self.alloc_unicode(u"abcdef") @@ -1128,12 +1128,12 @@ r_box = self.alloc_unicode(u"!???????!") if r_box_is_const: r_box = r_box.constbox() - self.execute_operation(rop.COPYUNICODECONTENT, - [s_box, r_box, - srcstart_box, - dststart_box, - length_box], 'void') - assert self.look_unicode(r_box) == u"!??cdef?!" + self.execute_operation(rop.COPYUNICODECONTENT, + [s_box, r_box, + srcstart_box, + dststart_box, + length_box], 'void') + assert self.look_unicode(r_box) == u"!??cdef?!" def test_do_unicode_basic(self): u = self.cpu.bh_newunicode(5) From noreply at buildbot.pypy.org Sun Sep 6 11:19:34 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 11:19:34 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix test_util.py Message-ID: <20150906091934.28F0D1C1453@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79470:4e33c7bf451c Date: 2015-09-06 11:09 +0200 http://bitbucket.org/pypy/pypy/changeset/4e33c7bf451c/ Log: fix test_util.py 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 @@ -12,7 +12,7 @@ from rpython.jit.metainterp.optimizeopt.util import sort_descrs, equaloplists from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.metainterp.logger import LogOperations -from rpython.jit.tool.oparser import OpParser +from rpython.jit.tool.oparser import OpParser, pure_parse from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr from rpython.jit.metainterp import compile, resume, history from rpython.jit.metainterp.jitprof import EmptyProfiler @@ -35,6 +35,12 @@ sort_descrs(lst2) assert lst2 == lst +def make_remap(inp1, inp2): + remap = {} + for a, b in zip(inp1, inp2): + remap[b] = a + return remap + def test_equaloplists(): ops = """ [i0] @@ -48,9 +54,12 @@ loop2 = pure_parse(ops, namespace=namespace) loop3 = pure_parse(ops.replace("i2 = int_add", "i2 = int_sub"), namespace=namespace) - assert equaloplists(loop1.operations, loop2.operations) + assert equaloplists(loop1.operations, loop2.operations, + remap=make_remap(loop1.inputargs, + loop2.inputargs)) py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") + "equaloplists(loop1.operations, loop3.operations," + "remap=make_remap(loop1.inputargs, loop3.inputargs))") def test_equaloplists_fail_args(): ops = """ @@ -65,13 +74,16 @@ loop2 = pure_parse(ops.replace("[i2, i1]", "[i1, i2]"), namespace=namespace) py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop2.operations)") + "equaloplists(loop1.operations, loop2.operations," + "remap=make_remap(loop1.inputargs, loop2.inputargs))") assert equaloplists(loop1.operations, loop2.operations, + remap=make_remap(loop1.inputargs, loop2.inputargs), strict_fail_args=False) loop3 = pure_parse(ops.replace("[i2, i1]", "[i2, i0]"), namespace=namespace) py.test.raises(AssertionError, - "equaloplists(loop1.operations, loop3.operations)") + "equaloplists(loop1.operations, loop3.operations," + " remap=make_remap(loop1.inputargs, loop3.inputargs))") # ____________________________________________________________ From noreply at buildbot.pypy.org Sun Sep 6 11:19:36 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 11:19:36 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: let's not forget Message-ID: <20150906091936.39BE41C1453@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79471:03697d696cd2 Date: 2015-09-06 11:19 +0200 http://bitbucket.org/pypy/pypy/changeset/03697d696cd2/ Log: let's not forget diff --git a/rpython/jit/metainterp/optimizeopt/TODO b/rpython/jit/metainterp/optimizeopt/TODO --- a/rpython/jit/metainterp/optimizeopt/TODO +++ b/rpython/jit/metainterp/optimizeopt/TODO @@ -1,4 +1,5 @@ -* mark_opaque_pointer is ignored (which is fine until unrolling) -* implement unrolling * implement more cases of copying _fields and _items between normal info - and ConstPtrInfo when proven constant + and ConstPtrInfo when proven constant (look at it) +* reenable cpu check (breaks --fork-before) +* reenable jit iface +* fix OS X, win, arm, 32bit diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -436,7 +436,7 @@ value1 = ConstIntBound(1) box = InputArgInt() guards = [] - value1.make_guards(box, guards) + value1.make_guards(box, guards, FakeOptimizer(self.cpu)) expected = """ [i0] guard_value(i0, 1) [] diff --git a/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py b/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py --- a/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_zdisable_opts.py @@ -1,7 +1,11 @@ + +import py from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import OptimizeOptTest from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.resoperation import rop +def setup_module(mod): + py.test.skip("purpose unclear") allopts = OptimizeOptTest.enable_opts.split(':') for optnum in range(len(allopts)): From noreply at buildbot.pypy.org Sun Sep 6 12:23:21 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 12:23:21 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: 32bit: fix test_executor.py Message-ID: <20150906102321.3A6871C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79472:0156d890d463 Date: 2015-09-06 12:05 +0200 http://bitbucket.org/pypy/pypy/changeset/0156d890d463/ Log: 32bit: fix test_executor.py diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -470,8 +470,10 @@ return ConstInt(value) elif isinstance(value, bool): return ConstInt(int(value)) + elif lltype.typeOf(value) == longlong.FLOATSTORAGE: + return ConstFloat(value) elif isinstance(value, float): - return ConstFloat(value) + return ConstFloat(longlong.getfloatstorage(value)) else: assert lltype.typeOf(value) == llmemory.GCREF return ConstPtr(value) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -404,6 +404,7 @@ getfloat = getfloatstorage def setfloatstorage(self, floatval): + assert lltype.typeOf(floatval) is longlong.FLOATSTORAGE self._resfloat = floatval def copy_value_from(self, other): @@ -478,7 +479,7 @@ self.setint(intval) class InputArgFloat(FloatOp, AbstractInputArg): - def __init__(self, f=0.0): + def __init__(self, f=longlong.ZEROF): self.setfloatstorage(f) class InputArgRef(RefOp, AbstractInputArg): diff --git a/rpython/jit/metainterp/test/test_executor.py b/rpython/jit/metainterp/test/test_executor.py --- a/rpython/jit/metainterp/test/test_executor.py +++ b/rpython/jit/metainterp/test/test_executor.py @@ -84,7 +84,7 @@ argboxes = [InputArgInt(99999), InputArgInt(321), constfloat(2.25), ConstInt(123), InputArgRef(), boxfloat(5.5)] box = execute_varargs(cpu, FakeMetaInterp(), rop.CALL_F, argboxes, descr) - assert box == 42.5 + assert longlong.getrealfloat(box) == 42.5 assert cpu.fakecalled == (99999, [321, 123], [ConstPtr.value], [longlong.getfloatstorage(2.25), @@ -99,7 +99,7 @@ argboxes = [InputArgInt(321), ConstInt(123)] box = _execute_arglist(cpu, FakeMetaInterp(), rop.CALL_F, argboxes, FakeCallDescr()) - assert box == 42.5 + assert longlong.getrealfloat(box) == 42.5 # arity == 0 box = _execute_arglist(cpu, None, rop.NEW, [], descr) assert box.fakeargs == ('new', descr) @@ -298,7 +298,7 @@ boxargs = [] for x in args: if isinstance(x, float): - boxargs.append(InputArgFloat(x)) + boxargs.append(boxfloat(x)) else: boxargs.append(InputArgInt(x)) yield opnum, boxargs, rettype, retvalue @@ -309,13 +309,15 @@ if (isinstance(args[0], float) and isinstance(args[1], float) and args[0] == args[1]): - commonbox = InputArgFloat(args[0]) + commonbox = boxfloat(args[0]) yield opnum, [commonbox, commonbox], rettype, retvalue def test_float_ops(): cpu = FakeCPU() for opnum, boxargs, rettype, retvalue in get_float_tests(cpu): res = _execute_arglist(cpu, None, opnum, boxargs) + if rettype == 'float': + res = longlong.getrealfloat(res) assert res == retvalue def make_args_for_op(op, a, b): From noreply at buildbot.pypy.org Sun Sep 6 12:23:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 12:23:23 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: 32bit: fix fix fix Message-ID: <20150906102323.5E6541C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79473:27475ddd1350 Date: 2015-09-06 12:23 +0200 http://bitbucket.org/pypy/pypy/changeset/27475ddd1350/ Log: 32bit: fix fix fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -27,11 +27,8 @@ IS_32_BIT = sys.maxint < 2**32 IS_64_BIT = sys.maxint > 2**32 -def constfloat(x): - return ConstFloat(longlong.getfloatstorage(x)) - -def boxfloat(x): - return InputArgFloat(longlong.getfloatstorage(x)) +boxfloat = InputArgFloat.fromfloat +constfloat = ConstFloat.fromfloat def clone(op): if op.type == 'i': @@ -421,6 +418,8 @@ from rpython.jit.metainterp.test.test_executor import get_float_tests for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu): res = self.execute_operation(opnum, boxargs, rettype) + if rettype == 'float': + res = longlong.getrealfloat(res) assert res == retvalue def test_ovf_operations(self, reversed=False): @@ -563,7 +562,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) - assert abs(res - 4.6) < 0.0001 + assert abs(longlong.getrealfloat(res) - 4.6) < 0.0001 def test_call_many_arguments(self): # Test calling a function with a large number of arguments (more than @@ -648,7 +647,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox, constfloat(1.5), constfloat(2.5)], 'float', descr=calldescr) - assert res == 4.0 + assert longlong.getrealfloat(res) == 4.0 def test_field_basic(self): @@ -706,13 +705,13 @@ 'void', descr=floatdescr) res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res == 3.4 + assert longlong.getrealfloat(res) == 3.4 # self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)], 'void', descr=floatdescr) res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res == -3.6 + assert longlong.getrealfloat(res) == -3.6 def test_passing_guards(self): @@ -933,10 +932,10 @@ 'void', descr=arraydescr) r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(1)], 'float', descr=arraydescr) - assert r == 3.5 + assert longlong.getrealfloat(r) == 3.5 r = self.execute_operation(rop.GETARRAYITEM_GC_F, [a_box, InputArgInt(2)], 'float', descr=arraydescr) - assert r == 4.5 + assert longlong.getrealfloat(r) == 4.5 # For platforms where sizeof(INT) != sizeof(Signed) (ie, x86-64) a_box, A = self.alloc_array_of(rffi.INT, 342) @@ -979,7 +978,7 @@ self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, longlong.getfloatstorage(2.5), kdescr) r = self.execute_operation(rop.GETINTERIORFIELD_GC_F, [a_box, InputArgInt(3)], 'float', descr=kdescr) - assert r == 2.5 + assert longlong.getrealfloat(r) == 2.5 # NUMBER_FIELDS = [('vs', lltype.Signed), ('vu', lltype.Unsigned), @@ -1133,9 +1132,9 @@ if self.cpu.supports_floats: r = self.execute_operation(rop.SAME_AS_F, [constfloat(5.5)], 'float') - assert r == 5.5 + assert longlong.getrealfloat(r) == 5.5 r = self.execute_operation(rop.SAME_AS_F, [boxfloat(5.5)], 'float') - assert r == 5.5 + assert longlong.getrealfloat(r) == 5.5 def test_virtual_ref(self): pass # VIRTUAL_REF must not reach the backend nowadays @@ -4128,7 +4127,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox, boxfloat(arg)], 'float', descr=calldescr) - assert res == expected + assert longlong.getrealfloat(res) == expected def test_compile_loop_with_target(self): looptoken = JitCellToken() diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -270,6 +270,10 @@ assert lltype.typeOf(valuestorage) is longlong.FLOATSTORAGE self.value = valuestorage + @staticmethod + def fromfloat(x): + return ConstFloat(longlong.getfloatstorage(x)) + def getfloatstorage(self): return self.value diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -482,6 +482,10 @@ def __init__(self, f=longlong.ZEROF): self.setfloatstorage(f) + @staticmethod + def fromfloat(x): + return InputArgFloat(longlong.getfloatstorage(x)) + class InputArgRef(RefOp, AbstractInputArg): def __init__(self, r=lltype.nullptr(llmemory.GCREF.TO)): self.setref_base(r) diff --git a/rpython/jit/metainterp/test/test_executor.py b/rpython/jit/metainterp/test/test_executor.py --- a/rpython/jit/metainterp/test/test_executor.py +++ b/rpython/jit/metainterp/test/test_executor.py @@ -63,11 +63,9 @@ def bh_strsetitem(self, string, index, newvalue): self.fakestrsetitem = (string, index, newvalue) -def boxfloat(x): - return InputArgFloat(longlong.getfloatstorage(x)) -def constfloat(x): - return ConstFloat(longlong.getfloatstorage(x)) +boxfloat = InputArgFloat.fromfloat +constfloat = ConstFloat.fromfloat def test_execute(): diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -171,7 +171,7 @@ if elem.startswith('i'): v = InputArgInt(0) elif elem.startswith('f'): - v = InputArgFloat(0.0) + v = InputArgFloat.fromfloat(0.0) else: from rpython.rtyper.lltypesystem import lltype, llmemory assert elem.startswith('p') From noreply at buildbot.pypy.org Sun Sep 6 12:37:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 12:37:02 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: 32bit: fix fix fix Message-ID: <20150906103702.8E53E1C1457@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79474:b0cde222530f Date: 2015-09-06 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/b0cde222530f/ Log: 32bit: fix fix fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -1664,6 +1664,8 @@ expectedtype = 'int' got = self.execute_operation(opnum, inputargs, expectedtype) + if not isinstance(expected, bool): + got = longlong.getrealfloat(got) if isnan(expected): ok = isnan(got) elif isinf(expected): @@ -1765,9 +1767,9 @@ wait_a_bit() res2 = self.execute_operation(rop.CALL_I, [funcbox], 'int', calldescr) else: - res1 = self.execute_operation(rop.CALL_I, [funcbox],'float',calldescr) + res1 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr) wait_a_bit() - res2 = self.execute_operation(rop.CALL_I, [funcbox],'float',calldescr) + res2 = self.execute_operation(rop.CALL_F, [funcbox],'float',calldescr) assert res1 < res2 < res1 + 2**32 @@ -4008,9 +4010,10 @@ calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(self.cpu, f) - res = self.execute_operation(rop.CALL, [funcbox, BoxFloat(value)], + res = self.execute_operation(rop.CALL_F, + [funcbox, InputArgFloat(value)], 'float', descr=calldescr) - assert res.getfloatstorage() == expected + assert res == expected def test_singlefloat_result_of_call_direct(self): if not self.cpu.supports_singlefloats: diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py --- a/rpython/jit/backend/x86/test/test_runner.py +++ b/rpython/jit/backend/x86/test/test_runner.py @@ -481,10 +481,6 @@ funcbox = ConstInt(rawstart) i1 = InputArgInt() i2 = InputArgInt() - i3 = InputArgInt() - i4 = InputArgInt() - i5 = InputArgInt() - i6 = InputArgInt() c = ConstInt(-1) faildescr = BasicFailDescr(1) cz = ConstInt(0) @@ -493,29 +489,35 @@ # then we are going to get our stack emptied unexpectedly by # several repeated calls ops = [ - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [cz, funcbox, i1, c, c, c, c, c, c, c, c, i2], - i3, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [cz, funcbox, i1, c, c, c, c, c, c, c, c, i2], - i4, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [cz, funcbox, i1, c, c, c, c, c, c, c, c, i2], - i5, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [cz, funcbox, i1, c, c, c, c, c, c, c, c, i2], - i6, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), + ] + i3 = ops[0] + i4 = ops[2] + i5 = ops[4] + i6 = ops[6] - ResOperation(rop.GUARD_FALSE, [i3], None, + ops += [ + ResOperation(rop.GUARD_FALSE, [i3], descr=BasicFailDescr(0)), - ResOperation(rop.FINISH, [], None, + ResOperation(rop.FINISH, [], descr=BasicFinalDescr(1)) ] ops[-2].setfailargs([i3, i4, i5, i6]) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -706,7 +706,7 @@ 'CAST_INT_TO_FLOAT/1/f', # need some messy code in the backend 'CAST_FLOAT_TO_SINGLEFLOAT/1/i', 'CAST_SINGLEFLOAT_TO_FLOAT/1/f', - 'CONVERT_FLOAT_BYTES_TO_LONGLONG/1/i', + 'CONVERT_FLOAT_BYTES_TO_LONGLONG/1/' + ('i' if longlong.is_64_bit else 'f'), 'CONVERT_LONGLONG_BYTES_TO_FLOAT/1/f', # 'INT_LT/2b/i', From noreply at buildbot.pypy.org Sun Sep 6 14:16:45 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 14:16:45 +0200 (CEST) Subject: [pypy-commit] pypy default: Re-enable this optimization in the arm backend Message-ID: <20150906121645.A615C1C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79475:9b332571db85 Date: 2015-09-06 13:56 +0200 http://bitbucket.org/pypy/pypy/changeset/9b332571db85/ Log: Re-enable this optimization in the arm backend diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -760,7 +760,6 @@ # optimization only: fill in the 'hint_frame_locations' dictionary # of rm and xrm based on the JUMP at the end of the loop, by looking # at where we would like the boxes to be after the jump. - return # XXX disabled for now op = operations[-1] if op.getopnum() != rop.JUMP: return @@ -778,16 +777,16 @@ # we would like the boxes to be after the jump. def _compute_hint_frame_locations_from_descr(self, descr): - return - #arglocs = self.assembler.target_arglocs(descr) - #jump_op = self.final_jump_op - #assert len(arglocs) == jump_op.numargs() - #for i in range(jump_op.numargs()): - # box = jump_op.getarg(i) - # if isinstance(box, Box): - # loc = arglocs[i] - # if loc is not None and loc.is_stack(): - # self.frame_manager.hint_frame_locations[box] = loc + arglocs = self.assembler.target_arglocs(descr) + jump_op = self.final_jump_op + assert len(arglocs) == jump_op.numargs() + for i in range(jump_op.numargs()): + box = jump_op.getarg(i) + if isinstance(box, Box): + loc = arglocs[i] + if loc is not None and loc.is_stack(): + self.frame_manager.hint_frame_pos[box] = ( + self.fm.get_loc_index(loc)) def prepare_op_jump(self, op, fcond): assert self.jump_target_descr is None @@ -1218,9 +1217,9 @@ # end of the same loop, i.e. if what we are compiling is a single # loop that ends up jumping to this LABEL, then we can now provide # the hints about the expected position of the spilled variables. - #jump_op = self.final_jump_op - #if jump_op is not None and jump_op.getdescr() is descr: - # self._compute_hint_frame_locations_from_descr(descr) + jump_op = self.final_jump_op + if jump_op is not None and jump_op.getdescr() is descr: + self._compute_hint_frame_locations_from_descr(descr) return [] def prepare_op_guard_not_forced_2(self, op, fcond): From noreply at buildbot.pypy.org Sun Sep 6 14:16:47 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 14:16:47 +0200 (CEST) Subject: [pypy-commit] pypy default: oops. I broke the arm backend in 995518da4059 (found by running Message-ID: <20150906121647.B551C1C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79476:d8ef26e72e17 Date: 2015-09-06 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/d8ef26e72e17/ Log: oops. I broke the arm backend in 995518da4059 (found by running test_zll_stress) diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -937,7 +937,7 @@ opnum = op.getopnum() if op.has_no_side_effect() and op.result not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - if not we_are_translated() and op.getopnum() == -124: + elif not we_are_translated() and op.getopnum() == -124: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) From noreply at buildbot.pypy.org Sun Sep 6 14:20:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 14:20:23 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: in-progress Message-ID: <20150906122023.47B4F1C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79477:2db9160f97b7 Date: 2015-09-06 14:19 +0200 http://bitbucket.org/pypy/pypy/changeset/2db9160f97b7/ Log: in-progress diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -2,7 +2,7 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.codebuilder import InstrBuilder -from rpython.jit.metainterp.history import ConstInt, BoxInt, FLOAT +from rpython.jit.metainterp.history import FLOAT from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -1,14 +1,13 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r -from rpython.jit.metainterp.history import ConstInt, BoxInt, Box, FLOAT -from rpython.jit.metainterp.history import ConstInt +from rpython.jit.metainterp.history import Const, FLOAT from rpython.rlib.objectmodel import we_are_translated VMEM_imm_size=0x3FC default_imm_size=0xFF def check_imm_arg(arg, size=default_imm_size, allow_zero=True): - assert not isinstance(arg, ConstInt) + assert not isinstance(arg, Const) if not we_are_translated(): if not isinstance(arg, int): import pdb; pdb.set_trace() @@ -20,7 +19,7 @@ return i <= size and lower_bound def check_imm_box(arg, size=0xFF, allow_zero=True): - if isinstance(arg, ConstInt): + if isinstance(arg, Const): return check_imm_arg(arg.getint(), size, allow_zero) return False @@ -96,7 +95,7 @@ arg2 = self.rm.make_sure_var_in_reg(a1, selected_reg=r.r1) assert arg1 == r.r0 assert arg2 == r.r1 - if isinstance(a0, Box) and self.stays_alive(a0): + if not isinstance(a0, Const) and self.stays_alive(a0): self.force_spill_var(a0) self.possibly_free_vars_for_op(op) self.free_temp_vars() @@ -135,7 +134,6 @@ def f(self, op, guard_op, fcond): assert fcond is not None a0 = op.getarg(0) - assert isinstance(a0, Box) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) if guard_op is None: diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -2,7 +2,7 @@ from rpython.rlib import rgc from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.jit.backend.llsupport.regalloc import FrameManager, \ - RegisterManager, TempBox, compute_vars_longevity, BaseRegalloc, \ + RegisterManager, TempVar, compute_vars_longevity, BaseRegalloc, \ get_scale from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm import locations @@ -43,21 +43,21 @@ # that it is a LABEL that was not compiled yet. TargetToken._ll_loop_code = 0 -class TempInt(TempBox): +class TempInt(TempVar): type = INT def __repr__(self): return "" % (id(self),) -class TempPtr(TempBox): +class TempPtr(TempVar): type = REF def __repr__(self): return "" % (id(self),) -class TempFloat(TempBox): +class TempFloat(TempVar): type = FLOAT def __repr__(self): @@ -725,7 +725,7 @@ prepare_op_guard_nonnull_class = prepare_op_guard_class def _prepare_guard_class(self, op, fcond): - assert isinstance(op.getarg(0), Box) + assert not isinstance(op.getarg(0), Const) boxes = op.getarglist() x = self.make_sure_var_in_reg(boxes[0], boxes) @@ -1100,7 +1100,7 @@ def prepare_op_call_malloc_nursery_varsize_frame(self, op, fcond): size_box = op.getarg(0) - assert isinstance(size_box, BoxInt) # we cannot have a const here! + assert not isinstance(size_box, ConstInt) # we cannot have a const here! # sizeloc must be in a register, but we can free it now # (we take care explicitly of conflicts with r0 or r1) sizeloc = self.rm.make_sure_var_in_reg(size_box) @@ -1134,7 +1134,7 @@ # the result will be in r0 self.rm.force_allocate_reg(op.result, selected_reg=r.r0) # we need r1 as a temporary - tmp_box = TempBox() + tmp_box = TempVar() self.rm.force_allocate_reg(tmp_box, selected_reg=r.r1) gcmap = self.get_gcmap([r.r0, r.r1]) # allocate the gcmap *before* self.rm.possibly_free_var(tmp_box) diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -2,9 +2,9 @@ from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.backend.test.runner_test import LLtypeBackendTest,\ boxfloat, constfloat -from rpython.jit.metainterp.history import (BasicFailDescr, BasicFinalDescr, - BoxInt) -from rpython.jit.metainterp.resoperation import ResOperation, rop +from rpython.jit.metainterp.history import BasicFailDescr, BasicFinalDescr +from rpython.jit.metainterp.resoperation import (ResOperation, rop, + InputArgInt) from rpython.jit.tool.oparser import parse from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper import rclass @@ -52,30 +52,29 @@ def test_result_is_spilled(self): cpu = self.cpu - inp = [BoxInt(i) for i in range(1, 15)] - out = [BoxInt(i) for i in range(1, 15)] + inp = [InputArgInt(i) for i in range(1, 15)] looptoken = JitCellToken() targettoken = TargetToken() operations = [ ResOperation(rop.LABEL, inp, None, descr=targettoken), - ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[0]), - ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[1]), - ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[2]), - ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[3]), - ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[4]), - ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[5]), - ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[6]), - ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[7]), - ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[8]), - ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[9]), - ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[10]), - ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[11]), - ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[12]), - ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[13]), - ResOperation(rop.GUARD_FALSE, [inp[1]], None, descr=BasicFailDescr(1)), - ResOperation(rop.FINISH, [inp[1]], None, descr=BasicFinalDescr(1)), + ResOperation(rop.INT_ADD, [inp[0], inp[1]]), + ResOperation(rop.INT_ADD, [inp[2], inp[3]]), + ResOperation(rop.INT_ADD, [inp[4], inp[5]]), + ResOperation(rop.INT_ADD, [inp[6], inp[7]]), + ResOperation(rop.INT_ADD, [inp[8], inp[9]]), + ResOperation(rop.INT_ADD, [inp[10], inp[11]]), + ResOperation(rop.INT_ADD, [inp[12], inp[13]]), + ResOperation(rop.INT_ADD, [inp[0], inp[1]]), + ResOperation(rop.INT_ADD, [inp[2], inp[3]]), + ResOperation(rop.INT_ADD, [inp[4], inp[5]]), + ResOperation(rop.INT_ADD, [inp[6], inp[7]]), + ResOperation(rop.INT_ADD, [inp[8], inp[9]]), + ResOperation(rop.INT_ADD, [inp[10], inp[11]]), + ResOperation(rop.INT_ADD, [inp[12], inp[13]]), + ResOperation(rop.GUARD_FALSE, [inp[1]], descr=BasicFailDescr(1)), + ResOperation(rop.FINISH, [inp[1]], descr=BasicFinalDescr(1)), ] - operations[-2].setfailargs(out) + operations[-2].setfailargs(operations[1:15]) cpu.compile_loop(inp, operations, looptoken) args = [i for i in range(1, 15)] deadframe = self.cpu.execute_token(looptoken, *args) From noreply at buildbot.pypy.org Sun Sep 6 14:45:29 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 14:45:29 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: hg merge default Message-ID: <20150906124529.BA9EC1C11C8@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79478:11ec8e8ccf14 Date: 2015-09-06 14:41 +0200 http://bitbucket.org/pypy/pypy/changeset/11ec8e8ccf14/ Log: hg merge default diff too long, truncating to 2000 out of 4185 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -429,7 +430,7 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py --- a/lib_pypy/_curses.py +++ b/lib_pypy/_curses.py @@ -1026,16 +1026,22 @@ def tigetflag(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetflag(capname) def tigetnum(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetnum(capname) def tigetstr(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') val = lib.tigetstr(capname) if int(ffi.cast("intptr_t", val)) in (0, -1): return None diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.2.1 +Version: 1.3.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.2.1" -__version_info__ = (1, 2, 1) +__version__ = "1.3.0" +__version_info__ = (1, 3, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -214,6 +214,12 @@ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -648,10 +648,21 @@ assert typenames[-1] == '__dotdotdot__' if len(typenames) == 1: return model.unknown_type(decl.name) - for t in typenames[:-1]: - if t not in ['int', 'short', 'long', 'signed', 'unsigned', 'char']: - raise api.FFIError(':%d: bad usage of "..."' % decl.coord.line) + + if (typenames[:-1] == ['float'] or + typenames[:-1] == ['double']): + # not for 'long double' so far + result = model.UnknownFloatType(decl.name) + else: + for t in typenames[:-1]: + if t not in ['int', 'short', 'long', 'signed', + 'unsigned', 'char']: + raise api.FFIError(':%d: bad usage of "..."' % + decl.coord.line) + result = model.UnknownIntegerType(decl.name) + if self._uses_new_feature is None: self._uses_new_feature = "'typedef %s... %s'" % ( ' '.join(typenames[:-1]), decl.name) - return model.UnknownIntegerType(decl.name) + + return result diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -158,12 +158,23 @@ self.c_name_with_marker = name + '&' def is_integer_type(self): - return True # for now + return True def build_backend_type(self, ffi, finishlist): raise NotImplementedError("integer type '%s' can only be used after " "compilation" % self.name) +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + class BaseFunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -79,7 +79,9 @@ #define _CFFI_PRIM_UINTMAX 47 #define _CFFI__NUM_PRIM 48 -#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) struct _cffi_global_s { diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -468,6 +468,10 @@ if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), tp.name.replace(' ', '_')) @@ -522,6 +526,8 @@ if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type(): return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double': return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: @@ -1107,6 +1113,12 @@ ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 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 @@ -5,3 +5,7 @@ .. this is a revision shortly after release-2.6.1 .. startrev: 07769be4057b +.. branch: keys_with_hash +Improve the performance of dict.update() and a bunch of methods from +sets, by reusing the hash value stored in one dict when inspecting +or changing another dict with that key. diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.2.1" +VERSION = "1.3.0" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -19,13 +19,27 @@ # ____________________________________________________________ +class Closure(object): + """This small class is here to have a __del__ outside any cycle.""" + + ll_error = lltype.nullptr(rffi.CCHARP.TO) # set manually + + def __init__(self, ptr): + self.ptr = ptr + + def __del__(self): + clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self.ptr)) + if self.ll_error: + lltype.free(self.ll_error, flavor='raw') + + class W_CDataCallback(W_CData): #_immutable_fields_ = ... - ll_error = lltype.nullptr(rffi.CCHARP.TO) w_onerror = None def __init__(self, space, ctype, w_callable, w_error, w_onerror): raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc()) + self._closure = Closure(raw_closure) W_CData.__init__(self, space, raw_closure, ctype) # if not space.is_true(space.callable(w_callable)): @@ -44,10 +58,11 @@ if size > 0: if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG: size = SIZE_OF_FFI_ARG - self.ll_error = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', - zero=True) + self._closure.ll_error = lltype.malloc(rffi.CCHARP.TO, size, + flavor='raw', zero=True) if not space.is_none(w_error): - convert_from_object_fficallback(fresult, self.ll_error, w_error) + convert_from_object_fficallback(fresult, self._closure.ll_error, + w_error) # self.unique_id = compute_unique_id(self) global_callback_mapping.set(self.unique_id, self) @@ -74,12 +89,6 @@ from pypy.module.thread.os_thread import setup_threads setup_threads(space) - #@rgc.must_be_light_finalizer - def __del__(self): - clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self._ptr)) - if self.ll_error: - lltype.free(self.ll_error, flavor='raw') - def _repr_extra(self): space = self.space return 'calling ' + space.str_w(space.repr(self.w_callable)) @@ -114,8 +123,8 @@ def write_error_return_value(self, ll_res): fresult = self.getfunctype().ctitem if fresult.size > 0: - misc._raw_memcopy(self.ll_error, ll_res, fresult.size) - keepalive_until_here(self) # to keep self.ll_error alive + misc._raw_memcopy(self._closure.ll_error, ll_res, fresult.size) + keepalive_until_here(self) # to keep self._closure.ll_error alive global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback) diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py --- a/pypy/module/_cffi_backend/cffi_opcode.py +++ b/pypy/module/_cffi_backend/cffi_opcode.py @@ -9,16 +9,16 @@ assert isinstance(self.arg, str) return '(_cffi_opcode_t)(%s)' % (self.arg,) classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg) + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) def as_python_bytes(self): - if self.op is None: - if self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): from .ffiplatform import VerificationError raise VerificationError("cannot emit to Python: %r" % (self.arg,)) return format_four_bytes((self.arg << 8) | self.op) @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -81,6 +81,13 @@ if num == cffi_opcode._UNKNOWN_PRIM: raise oefmt(ffi.w_FFIError, "primitive integer type with an " "unexpected size (or not an integer type at all)") + elif num == cffi_opcode._UNKNOWN_FLOAT_PRIM: + raise oefmt(ffi.w_FFIError, "primitive floating-point type with an " + "unexpected size (or not a float type at all)") + elif num == cffi_opcode._UNKNOWN_LONG_DOUBLE: + raise oefmt(ffi.w_FFIError, "primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") else: raise oefmt(space.w_NotImplementedError, "prim=%d", num) realize_cache = space.fromcache(RealizeCache) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,6 +1,9 @@ # ____________________________________________________________ import sys +assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" + " of cffi that differs from the one that we" + " get from 'import _cffi_backend'") if sys.version_info < (3,): type_or_class = "type" mandatory_b_prefix = '' @@ -3424,7 +3427,3 @@ "be 'foo *', but the types are different (check " "that you are not e.g. mixing up different ffi " "instances)") - -def test_version(): - # this test is here mostly for PyPy - assert __version__ == "1.2.1" diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1,7 +1,7 @@ # Generated by pypy/tool/import_cffi.py import sys, os, py -from cffi import FFI, VerificationError +from cffi import FFI, VerificationError, FFIError from cffi import recompiler from pypy.module.test_lib_pypy.cffi_tests.udir import udir from pypy.module.test_lib_pypy.cffi_tests.support import u @@ -1057,14 +1057,54 @@ assert lib.nu == 20 def test_some_float_type(): - py.test.skip("later") ffi = FFI() - ffi.cdef("typedef double... foo_t; foo_t sum(foo_t[]);") + ffi.cdef(""" + typedef double... foo_t; + typedef float... bar_t; + foo_t sum(foo_t[]); + bar_t neg(bar_t); + """) lib = verify(ffi, 'test_some_float_type', """ typedef float foo_t; static foo_t sum(foo_t x[]) { return x[0] + x[1]; } + typedef double bar_t; + static double neg(double x) { return -x; } """) assert lib.sum([40.0, 2.25]) == 42.25 + assert lib.sum([12.3, 45.6]) != 12.3 + 45.6 # precision loss + assert lib.neg(12.3) == -12.3 # no precision loss + assert ffi.sizeof("foo_t") == ffi.sizeof("float") + assert ffi.sizeof("bar_t") == ffi.sizeof("double") + +def test_some_float_invalid_1(): + ffi = FFI() + py.test.raises(FFIError, ffi.cdef, "typedef long double... foo_t;") + +def test_some_float_invalid_2(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_2', """ + typedef unsigned long foo_t; + foo_t neg(foo_t x) { return -x; } + """) + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type with an unexpected " + "size (or not a float type at all)") + +def test_some_float_invalid_3(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_3', """ + typedef long double foo_t; + foo_t neg(foo_t x) { return -x; } + """) + if ffi.sizeof("long double") == ffi.sizeof("double"): + assert lib.neg(12.3) == -12.3 + else: + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") def test_issue200(): ffi = FFI() diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,12 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): @@ -989,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1020,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1105,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1125,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1152,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -520,26 +520,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -4492,6 +4492,15 @@ with py.test.raises(annmodel.AnnotatorError): a.build_types(f, [int]) + def test_dict_can_be_none_ordering_issue(self): + def g(d): + return 42 in d + def f(n): + g(None) + g({}) + a = self.RPythonAnnotator() + a.build_types(f, [int]) + def g(n): return [0, 1, 2, n] diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -11,11 +12,13 @@ SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue, - s_Bool, s_None, unionof, add_knowntypedata, + s_Bool, s_None, s_Int, unionof, add_knowntypedata, HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray) from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -46,6 +49,16 @@ return s_Bool contains_SomeObject.can_only_throw = [] + at op.contains.register(SomeNone) +def contains_SomeNone(annotator, obj, element): + # return False here for the case "... in None", because it can be later + # generalized to "... in d" where d is either None or the empty dict + # (which would also return the constant False) + s_bool = SomeBool() + s_bool.const = False + return s_bool +contains_SomeNone.can_only_throw = [] + @op.simple_call.register(SomeObject) def simple_call_SomeObject(annotator, func, *args): return annotator.annotation(func).call( @@ -364,20 +377,19 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - at op.contains.register(SomeDict) -def contains_SomeDict(annotator, dct, element): - annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) - if annotator.annotation(dct)._is_empty(): +def dict_contains(s_dct, s_element): + s_dct.dictdef.generalize_key(s_element) + if s_dct._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool -contains_SomeDict.can_only_throw = _can_only_throw + + at op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + return dict_contains(annotator.annotation(dct), + annotator.annotation(element)) +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -401,16 +413,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -448,6 +466,12 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass @@ -460,6 +484,22 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/doc/conf.py b/rpython/doc/conf.py --- a/rpython/doc/conf.py +++ b/rpython/doc/conf.py @@ -68,7 +68,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -12,8 +12,7 @@ from rpython.jit.backend.arm.opassembler import ResOpAssembler from rpython.jit.backend.arm.regalloc import (Regalloc, CoreRegisterManager, check_imm_arg, VFPRegisterManager, - operations as regalloc_operations, - operations_with_guard as regalloc_operations_with_guard) + operations as regalloc_operations) from rpython.jit.backend.llsupport import jitframe, rewrite from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER, debug_bridge, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale, valid_addressing_size @@ -645,8 +644,10 @@ size_excluding_failure_stuff - loop_head) def _assemble(self, regalloc, inputargs, operations): + self.guard_success_cc = c.cond_none regalloc.compute_hint_frame_locations(operations) self._walk_operations(inputargs, operations, regalloc) + assert self.guard_success_cc == c.cond_none frame_depth = regalloc.get_final_frame_depth() jump_target_descr = regalloc.jump_target_descr if jump_target_descr is not None: @@ -927,6 +928,7 @@ def _walk_operations(self, inputargs, operations, regalloc): fcond = c.AL self._regalloc = regalloc + regalloc.operations = operations while regalloc.position() < len(operations) - 1: regalloc.next_instruction() i = regalloc.position() @@ -935,17 +937,6 @@ opnum = op.getopnum() if op.has_no_side_effect() and op.result not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif self._regalloc.can_merge_with_next_guard(op, i, operations): - guard = operations[i + 1] - assert guard.is_guard() - arglocs = regalloc_operations_with_guard[opnum](regalloc, op, - guard, fcond) - fcond = asm_operations_with_guard[opnum](self, op, - guard, arglocs, regalloc, fcond) - assert fcond is not None - regalloc.next_instruction() - regalloc.possibly_free_vars_for_op(guard) - regalloc.possibly_free_vars(guard.getfailargs()) elif not we_are_translated() and op.getopnum() == -124: regalloc.prepare_force_spill(op, fcond) else: @@ -962,6 +953,7 @@ regalloc.free_temp_vars() regalloc._check_invariants() self.mc.mark_op(None) # end of the loop + regalloc.operations = None def regalloc_emit_extra(self, op, arglocs, fcond, regalloc): # for calls to a function with a specifically-supported OS_xxx @@ -1516,21 +1508,11 @@ raise NotImplementedError(op) -def notimplemented_op_with_guard(self, op, guard_op, arglocs, regalloc, fcond): - print "[ARM/asm] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - asm_operations = [notimplemented_op] * (rop._LAST + 1) -asm_operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) asm_extra_operations = {} for name, value in ResOpAssembler.__dict__.iteritems(): - if name.startswith('emit_guard_'): - opname = name[len('emit_guard_'):] - num = getattr(rop, opname.upper()) - asm_operations_with_guard[num] = value - elif name.startswith('emit_opx_'): + if name.startswith('emit_opx_'): opname = name[len('emit_opx_'):] num = getattr(EffectInfo, 'OS_' + opname.upper()) asm_extra_operations[num] = value diff --git a/rpython/jit/backend/arm/conditions.py b/rpython/jit/backend/arm/conditions.py --- a/rpython/jit/backend/arm/conditions.py +++ b/rpython/jit/backend/arm/conditions.py @@ -13,11 +13,13 @@ GT = 0xC LE = 0xD AL = 0xE +cond_none = -1 opposites = [NE, EQ, CC, CS, PL, MI, VC, VS, LS, HI, LT, GE, LE, GT, AL] def get_opposite_of(operation): + assert operation >= 0 return opposites[operation] # see mapping for floating poin according to diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -6,33 +6,32 @@ from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop + +def flush_cc(asm, condition, result_loc): + # After emitting an instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to 'fp' by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert asm.guard_success_cc == c.cond_none + if result_loc is r.fp: + asm.guard_success_cc = condition + else: + asm.mc.MOV_ri(result_loc.value, 1, condition) + asm.mc.MOV_ri(result_loc.value, 0, c.get_opposite_of(condition)) + + def gen_emit_op_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None reg, res = arglocs self.mc.CMP_ri(reg.value, 0) - self.mc.MOV_ri(res.value, 1, true_cond) - self.mc.MOV_ri(res.value, 0, false_cond) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_guard_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert fcond is not None - assert guard is not None - reg = arglocs[0] - self.mc.CMP_ri(reg.value, 0) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[1:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_op_ri(name, opname): ri_op = getattr(InstrBuilder, '%s_ri' % opname) rr_op = getattr(InstrBuilder, '%s_rr' % opname) @@ -61,8 +60,7 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op(name, condition): - inv = c.get_opposite_of(condition) +def gen_emit_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs @@ -70,32 +68,11 @@ self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) else: self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=condition) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - l0 = arglocs[0] - l1 = arglocs[1] - assert l0.is_core_reg() - - if l1.is_imm(): - self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) - else: - self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - guard_opnum = guard.getopnum() - cond = true_cond - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): @@ -104,6 +81,7 @@ return fcond f.__name__ = 'emit_op_%s' % name return f + def gen_emit_unary_float_op(name, opname): op_rr = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): @@ -113,34 +91,16 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op(name, cond): - inv = c.get_opposite_of(cond) +def gen_emit_float_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): arg1, arg2, res = arglocs self.mc.VCMP(arg1.value, arg2.value) self.mc.VMRS(cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=cond) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_float_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None - arg1 = arglocs[0] - arg2 = arglocs[1] - self.mc.VCMP(arg1.value, arg2.value) - self.mc.VMRS(cond=fcond) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[2:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - class saved_registers(object): def __init__(self, cb, regs_to_save, vfp_regs_to_save=None): diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -49,42 +49,28 @@ f.__name__ = name return f -def prepare_float_op(name=None, base=True, float_result=True, guard=False): - if guard: - def f(self, op, guard_op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - else: - args = self._prepare_guard(guard_op, locs) - return args - else: - def f(self, op, fcond): - locs = [] - loc1 = self.make_sure_var_in_reg(op.getarg(0)) - locs.append(loc1) - if base: - loc2 = self.make_sure_var_in_reg(op.getarg(1)) - locs.append(loc2) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - res = self.force_allocate_reg(op.result) - assert float_result == (op.result.type == FLOAT) - locs.append(res) - return locs - if name: - f.__name__ = name - return f +def prepare_unary_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, res] + +def prepare_two_regs_op(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg(op.result) + return [loc1, loc2, res] + +def prepare_float_cmp(self, op, fcond): + loc1 = self.make_sure_var_in_reg(op.getarg(0)) + loc2 = self.make_sure_var_in_reg(op.getarg(1)) + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [loc1, loc2, res] def prepare_op_by_helper_call(name): def f(self, op, fcond): @@ -105,42 +91,28 @@ f.__name__ = name return f -def prepare_cmp_op(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - boxes = list(op.getarglist()) - arg0, arg1 = boxes - imm_a1 = check_imm_box(arg1) +def prepare_int_cmp(self, op, fcond): + assert fcond is not None + boxes = list(op.getarglist()) + arg0, arg1 = boxes + imm_a1 = check_imm_box(arg1) - l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) - if imm_a1: - l1 = self.convert_to_imm(arg1) - else: - l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) + l0 = self.make_sure_var_in_reg(arg0, forbidden_vars=boxes) + if imm_a1: + l1 = self.convert_to_imm(arg1) + else: + l1 = self.make_sure_var_in_reg(arg1, forbidden_vars=boxes) - self.possibly_free_vars_for_op(op) - self.free_temp_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - args = self._prepare_guard(guard_op, [l0, l1]) - return args - if name: - f.__name__ = name - return f + self.possibly_free_vars_for_op(op) + self.free_temp_vars() + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] -def prepare_op_unary_cmp(name=None): - def f(self, op, guard_op, fcond): - assert fcond is not None - a0 = op.getarg(0) - reg = self.make_sure_var_in_reg(a0) - self.possibly_free_vars_for_op(op) - if guard_op is None: - res = self.force_allocate_reg(op.result, [a0]) - return [reg, res] - else: - return self._prepare_guard(guard_op, [reg]) - if name: - f.__name__ = name - return f +def prepare_unary_cmp(self, op, fcond): + assert fcond is not None + a0 = op.getarg(0) + assert isinstance(a0, Box) + reg = self.make_sure_var_in_reg(a0) + self.possibly_free_vars_for_op(op) + res = self.force_allocate_reg_or_cc(op.result) + return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -5,13 +5,10 @@ from rpython.jit.backend.arm.arch import WORD, DOUBLE_WORD, JITFRAME_FIXED_SIZE from rpython.jit.backend.arm.helper.assembler import (gen_emit_op_by_helper_call, gen_emit_op_unary_cmp, - gen_emit_guard_unary_cmp, gen_emit_op_ri, gen_emit_cmp_op, - gen_emit_cmp_op_guard, gen_emit_float_op, gen_emit_float_cmp_op, - gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg @@ -114,32 +111,25 @@ return fcond #ref: http://blogs.arm.com/software-enablement/detecting-overflow-from-mul/ - def emit_guard_int_mul_ovf(self, op, guard, arglocs, regalloc, fcond): + def emit_op_int_mul_ovf(self, op, arglocs, regalloc, fcond): reg1 = arglocs[0] reg2 = arglocs[1] res = arglocs[2] - failargs = arglocs[3:] self.mc.SMULL(res.value, r.ip.value, reg1.value, reg2.value, cond=fcond) self.mc.CMP_rr(r.ip.value, res.value, shifttype=shift.ASR, imm=31, cond=fcond) - - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.NE, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.EQ, save_exc=False) - else: - assert 0 + self.guard_success_cc = c.EQ return fcond - def emit_guard_int_add_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_add_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_add_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_add_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond - def emit_guard_int_sub_ovf(self, op, guard, arglocs, regalloc, fcond): - self.int_sub_impl(op, arglocs[0:3], regalloc, fcond, flags=True) - self._emit_guard_overflow(guard, arglocs[3:], fcond) + def emit_op_int_sub_ovf(self, op, arglocs, regalloc, fcond): + fcond = self.int_sub_impl(op, arglocs, regalloc, fcond, flags=True) + self.guard_success_cc = c.VC return fcond emit_op_int_floordiv = gen_emit_op_by_helper_call('int_floordiv', 'DIV') @@ -160,37 +150,17 @@ emit_op_int_gt = gen_emit_cmp_op('int_gt', c.GT) emit_op_int_ge = gen_emit_cmp_op('int_ge', c.GE) - emit_guard_int_lt = gen_emit_cmp_op_guard('int_lt', c.LT) - emit_guard_int_le = gen_emit_cmp_op_guard('int_le', c.LE) - emit_guard_int_eq = gen_emit_cmp_op_guard('int_eq', c.EQ) - emit_guard_int_ne = gen_emit_cmp_op_guard('int_ne', c.NE) - emit_guard_int_gt = gen_emit_cmp_op_guard('int_gt', c.GT) - emit_guard_int_ge = gen_emit_cmp_op_guard('int_ge', c.GE) - emit_op_uint_le = gen_emit_cmp_op('uint_le', c.LS) emit_op_uint_gt = gen_emit_cmp_op('uint_gt', c.HI) emit_op_uint_lt = gen_emit_cmp_op('uint_lt', c.LO) emit_op_uint_ge = gen_emit_cmp_op('uint_ge', c.HS) - emit_guard_uint_le = gen_emit_cmp_op_guard('uint_le', c.LS) - emit_guard_uint_gt = gen_emit_cmp_op_guard('uint_gt', c.HI) - emit_guard_uint_lt = gen_emit_cmp_op_guard('uint_lt', c.LO) - emit_guard_uint_ge = gen_emit_cmp_op_guard('uint_ge', c.HS) - emit_op_ptr_eq = emit_op_instance_ptr_eq = emit_op_int_eq emit_op_ptr_ne = emit_op_instance_ptr_ne = emit_op_int_ne - emit_guard_ptr_eq = emit_guard_instance_ptr_eq = emit_guard_int_eq - emit_guard_ptr_ne = emit_guard_instance_ptr_ne = emit_guard_int_ne - - emit_op_int_add_ovf = emit_op_int_add - emit_op_int_sub_ovf = emit_op_int_sub emit_op_int_is_true = gen_emit_op_unary_cmp('int_is_true', c.NE) emit_op_int_is_zero = gen_emit_op_unary_cmp('int_is_zero', c.EQ) - emit_guard_int_is_true = gen_emit_guard_unary_cmp('int_is_true', c.NE) - emit_guard_int_is_zero = gen_emit_guard_unary_cmp('int_is_zero', c.EQ) - def emit_op_int_invert(self, op, arglocs, regalloc, fcond): reg, res = arglocs @@ -223,9 +193,15 @@ fcond=fcond) return token - def _emit_guard(self, op, arglocs, fcond, save_exc, + def _emit_guard(self, op, arglocs, save_exc, is_guard_not_invalidated=False, is_guard_not_forced=False): + if is_guard_not_invalidated: + fcond = c.cond_none + else: + fcond = self.guard_success_cc + self.guard_success_cc = c.cond_none + assert fcond != c.cond_none pos = self.mc.currpos() token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond, save_exc, is_guard_not_invalidated, @@ -241,27 +217,13 @@ self.mc.BKPT() return c.AL - def _emit_guard_overflow(self, guard, failargs, fcond): - if guard.getopnum() == rop.GUARD_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VS, save_exc=False) - elif guard.getopnum() == rop.GUARD_NO_OVERFLOW: - fcond = self._emit_guard(guard, failargs, c.VC, save_exc=False) - else: - assert 0 - return fcond - def emit_op_guard_true(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.NE, save_exc=False) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_false(self, op, arglocs, regalloc, fcond): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.CMP_ri(l0.value, 0) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.get_opposite_of(self.guard_success_cc) + fcond = self._emit_guard(op, arglocs, save_exc=False) return fcond def emit_op_guard_value(self, op, arglocs, regalloc, fcond): @@ -278,27 +240,27 @@ assert l1.is_vfp_reg() self.mc.VCMP(l0.value, l1.value) self.mc.VMRS(cond=fcond) - fcond = self._emit_guard(op, failargs, c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=False) return fcond emit_op_guard_nonnull = emit_op_guard_true emit_op_guard_isnull = emit_op_guard_false - def emit_op_guard_no_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VC, save_exc=False) - - def emit_op_guard_overflow(self, op, arglocs, regalloc, fcond): - return self._emit_guard(op, arglocs, c.VS, save_exc=False) + emit_op_guard_no_overflow = emit_op_guard_true + emit_op_guard_overflow = emit_op_guard_false def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) - self._emit_guard(op, arglocs[3:], c.EQ, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:], save_exc=False) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): @@ -315,18 +277,20 @@ self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - return self._emit_guard(op, locs, fcond, save_exc=False, + return self._emit_guard(op, locs, save_exc=False, is_guard_not_invalidated=True) def emit_op_label(self, op, arglocs, regalloc, fcond): self._check_frame_depth_debug(self.mc) return fcond - def cond_call(self, op, gcmap, cond_loc, call_loc, fcond): + def emit_op_cond_call(self, op, arglocs, regalloc, fcond): + [call_loc] = arglocs + gcmap = regalloc.get_gcmap([call_loc]) + assert call_loc is r.r4 - self.mc.TST_rr(cond_loc.value, cond_loc.value) jmp_adr = self.mc.currpos() - self.mc.BKPT() # patched later + self.mc.BKPT() # patched later: the conditional jump # self.push_gcmap(self.mc, gcmap, store=True) # @@ -344,8 +308,13 @@ self.mc.BL(cond_call_adr) self.pop_gcmap(self.mc) # never any result value + cond = c.get_opposite_of(self.guard_success_cc) + self.guard_success_cc = c.cond_none pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) - pmc.B_offs(self.mc.currpos(), c.EQ) # equivalent to 0 as result of TST above + pmc.B_offs(self.mc.currpos(), cond) + # might be overridden again to skip over the following + # guard_no_exception too + self.previous_cond_call_jcond = jmp_adr, cond return fcond def emit_op_jump(self, op, arglocs, regalloc, fcond): @@ -441,8 +410,15 @@ failargs = arglocs[1:] self.mc.LDR_ri(loc.value, loc.value) self.mc.CMP_ri(loc.value, 0) - cond = self._emit_guard(op, failargs, c.EQ, save_exc=True) - return cond + self.guard_success_cc = c.EQ + fcond = self._emit_guard(op, failargs, save_exc=True) + # If the previous operation was a COND_CALL, overwrite its conditional + # jump to jump over this GUARD_NO_EXCEPTION as well, if we can + if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: + jmp_adr, prev_cond = self.previous_cond_call_jcond + pmc = OverwritingBuilder(self.mc, jmp_adr, WORD) + pmc.B_offs(self.mc.currpos(), prev_cond) + return fcond def emit_op_guard_exception(self, op, arglocs, regalloc, fcond): loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] @@ -451,7 +427,8 @@ self.mc.LDR_ri(r.ip.value, loc1.value) self.mc.CMP_rr(r.ip.value, loc.value) - self._emit_guard(op, failargs, c.EQ, save_exc=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, failargs, save_exc=True) self._store_and_reset_exception(self.mc, resloc) return fcond @@ -975,16 +952,14 @@ def imm(self, v): return imm(v) - def emit_guard_call_assembler(self, op, guard_op, arglocs, regalloc, - fcond): + def emit_op_call_assembler(self, op, arglocs, regalloc, fcond): if len(arglocs) == 4: [argloc, vloc, result_loc, tmploc] = arglocs else: [argloc, result_loc, tmploc] = arglocs vloc = imm(0) - self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) - self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op)) + self._store_force_index(self._find_nearby_operation(+1)) + self.call_assembler(op, argloc, vloc, result_loc, tmploc) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): @@ -1058,41 +1033,37 @@ mc.B(target) mc.copy_to_raw_memory(oldadr) - def emit_guard_call_may_force(self, op, guard_op, arglocs, regalloc, - fcond): - self._store_force_index(guard_op) - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] - # - self._emit_call(op, callargs, fcond=fcond) - self._emit_guard_may_force(guard_op, guardargs) - return fcond - - def _emit_guard_may_force(self, guard_op, arglocs): + def emit_op_guard_not_forced(self, op, arglocs, regalloc, fcond): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) - self._emit_guard(guard_op, arglocs, c.EQ, - save_exc=True, is_guard_not_forced=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) + return fcond - def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, - fcond): - numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call - guardargs = arglocs[len(callargs):] # extrat the arguments for the guard - self._store_force_index(guard_op) - self._emit_call(op, callargs, is_call_release_gil=True) - self._emit_guard_may_force(guard_op, guardargs) + def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, fcond=fcond) + return fcond + + def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond): + self._store_force_index(self._find_nearby_operation(+1)) + self._emit_call(op, arglocs, is_call_release_gil=True) return fcond def _store_force_index(self, guard_op): + assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or + guard_op.getopnum() == rop.GUARD_NOT_FORCED_2) faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') value = rffi.cast(lltype.Signed, cast_instance_to_gcref(faildescr)) self.mc.gen_load_int(r.ip.value, value) self.store_reg(self.mc, r.ip, r.fp, ofs) + def _find_nearby_operation(self, delta): + regalloc = self._regalloc + return regalloc.operations[regalloc.rm.position + delta] + def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): self.emit_op_call(op, arglocs, regalloc, fcond) self.propagate_memoryerror_if_r0_is_null() @@ -1125,13 +1096,6 @@ emit_op_float_gt = gen_emit_float_cmp_op('float_gt', c.GT) emit_op_float_ge = gen_emit_float_cmp_op('float_ge', c.GE) - emit_guard_float_lt = gen_emit_float_cmp_op_guard('float_lt', c.VFP_LT) - emit_guard_float_le = gen_emit_float_cmp_op_guard('float_le', c.VFP_LE) - emit_guard_float_eq = gen_emit_float_cmp_op_guard('float_eq', c.EQ) - emit_guard_float_ne = gen_emit_float_cmp_op_guard('float_ne', c.NE) - emit_guard_float_gt = gen_emit_float_cmp_op_guard('float_gt', c.GT) - emit_guard_float_ge = gen_emit_float_cmp_op_guard('float_ge', c.GE) - def emit_op_cast_float_to_int(self, op, arglocs, regalloc, fcond): arg, res = arglocs assert arg.is_vfp_reg() diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -5,13 +5,16 @@ RegisterManager, TempVar, compute_vars_longevity, BaseRegalloc, \ get_scale from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import locations from rpython.jit.backend.arm.locations import imm, get_fp_offset from rpython.jit.backend.arm.helper.regalloc import (prepare_op_by_helper_call, - prepare_op_unary_cmp, + prepare_unary_cmp, prepare_op_ri, - prepare_cmp_op, - prepare_float_op, + prepare_int_cmp, + prepare_unary_op, + prepare_two_regs_op, + prepare_float_cmp, check_imm_arg, check_imm_box, VMEM_imm_size, @@ -146,6 +149,7 @@ box_types = None # or a list of acceptable types no_lower_byte_regs = all_regs save_around_call_regs = r.caller_resp + frame_reg = r.fp def __init__(self, longevity, frame_manager=None, assembler=None): RegisterManager.__init__(self, longevity, frame_manager, assembler) @@ -235,6 +239,18 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_allocate_reg_or_cc(self, var, forbidden_vars=[]): + assert var.type == INT + if self.next_op_can_accept_cc(self.operations, self.rm.position): + # hack: return the 'fp' location to mean "lives in CC". This + # fp will not actually be used, and the location will be freed + # after the next op as usual. + self.rm.force_allocate_frame_reg(var) + return r.fp + else: + # else, return a regular register (not fp). + return self.rm.force_allocate_reg(var) + def try_allocate_reg(self, v, selected_reg=None, need_lower_byte=False): if v.type == FLOAT: return self.vfprm.try_allocate_reg(v, selected_reg, @@ -467,25 +483,6 @@ resloc = self.force_allocate_reg(op.result) return [argloc, imm(numbytes), resloc] - def prepare_guard_int_mul_ovf(self, op, guard, fcond): - boxes = op.getarglist() - reg1 = self.make_sure_var_in_reg(boxes[0], forbidden_vars=boxes) - reg2 = self.make_sure_var_in_reg(boxes[1], forbidden_vars=boxes) - res = self.force_allocate_reg(op.result) - return self._prepare_guard(guard, [reg1, reg2, res]) - - def prepare_guard_int_add_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_add(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - - def prepare_guard_int_sub_ovf(self, op, guard, fcond): - locs = self._prepare_op_int_sub(op, fcond) - res = self.force_allocate_reg(op.result) - locs.append(res) - return self._prepare_guard(guard, locs) - prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') From noreply at buildbot.pypy.org Sun Sep 6 16:08:40 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 16:08:40 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Fix translation. Reduce the size of the constant attached to TEST. Message-ID: <20150906140840.1BB151C1453@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79479:bad77806a20f Date: 2015-09-06 16:08 +0200 http://bitbucket.org/pypy/pypy/changeset/bad77806a20f/ Log: Fix translation. Reduce the size of the constant attached to TEST. diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -706,13 +706,24 @@ def _setup_guard_is_object(self): from rpython.memory.gctypelayout import GCData, T_IS_RPYTHON_INSTANCE - self._infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, - 'infobits', True) - self._T_IS_RPYTHON_INSTANCE = T_IS_RPYTHON_INSTANCE + import struct + infobits_offset, _ = symbolic.get_field_token(GCData.TYPE_INFO, + 'infobits', True) + # compute the offset to the actual *byte*, and the byte mask + mask = struct.pack("l", T_IS_RPYTHON_INSTANCE) + assert mask.count('\x00') == len(mask) - 1 + infobits_offset_plus = 0 + while mask.startswith('\x00'): + infobits_offset_plus += 1 + mask = mask[1:] + self._infobits_offset = infobits_offset + self._infobits_offset_plus = infobits_offset_plus + self._T_IS_RPYTHON_INSTANCE_BYTE = ord(mask[0]) def get_translated_info_for_guard_is_object(self): infobits_offset = rffi.cast(lltype.Signed, self._infobits_offset) - return (infobits_offset, self._T_IS_RPYTHON_INSTANCE) + infobits_offset += self._infobits_offset_plus + return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE) # ____________________________________________________________ diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1357,24 +1357,24 @@ else: not_implemented("save_into_mem size = %d" % size) - def _genop_getfield_gc(self, op, arglocs, resloc): + def _genop_getfield(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, sign_loc = arglocs assert isinstance(size_loc, ImmedLoc) source_addr = AddressLoc(base_loc, ofs_loc) self.load_from_mem(resloc, source_addr, size_loc, sign_loc) - genop_getfield_gc_i = _genop_getfield_gc - genop_getfield_gc_r = _genop_getfield_gc - genop_getfield_gc_f = _genop_getfield_gc - genop_getfield_raw_i = _genop_getfield_gc - genop_getfield_raw_f = _genop_getfield_gc - genop_getfield_raw_pure_i = _genop_getfield_gc - genop_getfield_raw_pure_f = _genop_getfield_gc - genop_getfield_gc_pure_i = _genop_getfield_gc - genop_getfield_gc_pure_r = _genop_getfield_gc - genop_getfield_gc_pure_f = _genop_getfield_gc + genop_getfield_gc_i = _genop_getfield + genop_getfield_gc_r = _genop_getfield + genop_getfield_gc_f = _genop_getfield + genop_getfield_raw_i = _genop_getfield + genop_getfield_raw_f = _genop_getfield + genop_getfield_raw_pure_i = _genop_getfield + genop_getfield_raw_pure_f = _genop_getfield + genop_getfield_gc_pure_i = _genop_getfield + genop_getfield_gc_pure_r = _genop_getfield + genop_getfield_gc_pure_f = _genop_getfield - def _genop_getarrayitem_gc(self, op, arglocs, resloc): + def _genop_getarrayitem(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, ofs, sign_loc = arglocs assert isinstance(ofs, ImmedLoc) assert isinstance(size_loc, ImmedLoc) @@ -1382,16 +1382,16 @@ src_addr = addr_add(base_loc, ofs_loc, ofs.value, scale) self.load_from_mem(resloc, src_addr, size_loc, sign_loc) - genop_getarrayitem_gc_i = _genop_getarrayitem_gc - genop_getarrayitem_gc_r = _genop_getarrayitem_gc - genop_getarrayitem_gc_f = _genop_getarrayitem_gc - genop_getarrayitem_gc_pure_i = _genop_getarrayitem_gc - genop_getarrayitem_gc_pure_r = _genop_getarrayitem_gc - genop_getarrayitem_gc_pure_f = _genop_getarrayitem_gc - genop_getarrayitem_raw_i = _genop_getarrayitem_gc - genop_getarrayitem_raw_f = _genop_getarrayitem_gc - genop_getarrayitem_raw_pure_i = _genop_getarrayitem_gc - genop_getarrayitem_raw_pure_f = _genop_getarrayitem_gc + genop_getarrayitem_gc_i = _genop_getarrayitem + genop_getarrayitem_gc_r = _genop_getarrayitem + genop_getarrayitem_gc_f = _genop_getarrayitem + genop_getarrayitem_gc_pure_i = _genop_getarrayitem + genop_getarrayitem_gc_pure_r = _genop_getarrayitem + genop_getarrayitem_gc_pure_f = _genop_getarrayitem + genop_getarrayitem_raw_i = _genop_getarrayitem + genop_getarrayitem_raw_f = _genop_getarrayitem + genop_getarrayitem_raw_pure_i = _genop_getarrayitem + genop_getarrayitem_raw_pure_f = _genop_getarrayitem def _genop_raw_load(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, ofs, sign_loc = arglocs @@ -1446,16 +1446,16 @@ assert isinstance(ofs_loc, ImmedLoc) return AddressLoc(base_loc, temp_loc, shift, ofs_loc.value) - def _genop_getinteriorfield_gc(self, op, arglocs, resloc): + def _genop_getinteriorfield(self, op, arglocs, resloc): (base_loc, ofs_loc, itemsize_loc, fieldsize_loc, index_loc, temp_loc, sign_loc) = arglocs src_addr = self._get_interiorfield_addr(temp_loc, index_loc, itemsize_loc, base_loc, ofs_loc) self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc) - genop_getinteriorfield_gc_i = _genop_getinteriorfield_gc - genop_getinteriorfield_gc_r = _genop_getinteriorfield_gc - genop_getinteriorfield_gc_f = _genop_getinteriorfield_gc + genop_getinteriorfield_gc_i = _genop_getinteriorfield + genop_getinteriorfield_gc_r = _genop_getinteriorfield + genop_getinteriorfield_gc_f = _genop_getinteriorfield def genop_discard_increment_debug_counter(self, op, arglocs): # The argument should be an immediate address. This should @@ -1697,17 +1697,16 @@ self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) - def genop_guard_guard_gc_type(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_gc_type(self, guard_op, guard_token, locs, ign): self._cmp_guard_gc_type(locs[0], locs[1]) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) - def genop_guard_guard_is_object(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_is_object(self, guard_op, guard_token, locs, ign): assert self.cpu.supports_guard_gc_type [loc_object, loc_typeid] = locs - # idea: read the typeid, fetch the field 'infobits' from the big - # typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + # idea: read the typeid, fetch one byte of the field 'infobits' from + # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. if IS_X86_32: self.mc.MOVZX16(loc_typeid, mem(loc_object, 0)) else: @@ -1719,12 +1718,12 @@ self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by, offset=infobits_offset) - self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) + self.mc.TEST8(loc_infobits, imm(IS_OBJECT_FLAG)) # - self.implement_guard(guard_token, 'Z') + self.guard_success_cc = rx86.Conditions['NZ'] + self.implement_guard(guard_token) - def genop_guard_guard_subclass(self, op, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_subclass(self, guard_op, guard_token, locs, ign): assert self.cpu.supports_guard_gc_type [loc_object, loc_check_against_class, loc_tmp] = locs assert isinstance(loc_object, RegLoc) @@ -1757,8 +1756,9 @@ # check by doing the unsigned comparison (tmp - min) < (max - min) self.mc.SUB_ri(loc_tmp.value, check_min) self.mc.CMP_ri(loc_tmp.value, check_max - check_min) - # the guard fails if we get a "not below" result - self.implement_guard(guard_token, 'NB') + # the guard passes if we get a result of "below" + self.guard_success_cc = rx86.Conditions['B'] + self.implement_guard(guard_token) def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -671,6 +671,7 @@ CDQ = insn(rex_nw, '\x99') TEST8_mi = insn(rex_nw, '\xF6', orbyte(0<<3), mem_reg_plus_const(1), immediate(2, 'b')) + TEST8_ai = insn(rex_nw, '\xF6', orbyte(0<<3), mem_reg_plus_scaled_reg_plus_const(1), immediate(2, 'b')) TEST8_bi = insn(rex_nw, '\xF6', orbyte(0<<3), stack_bp(1), immediate(2, 'b')) TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_(1), immediate(2, 'b')) TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0') From noreply at buildbot.pypy.org Sun Sep 6 16:49:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 16:49:10 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: in-progress Message-ID: <20150906144910.ABEB81C0362@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79480:9d419227611e Date: 2015-09-06 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/9d419227611e/ Log: in-progress diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -708,7 +708,7 @@ self.fixup_target_tokens(rawstart) self.update_frame_depth(frame_depth) if logger: - logger.log_bridge(inputargs, operations, "rewritten", + logger.log_bridge(inputargs, operations, "rewritten", faildescr, ops_offset=ops_offset) self.teardown() @@ -935,9 +935,9 @@ op = operations[i] self.mc.mark_op(op) opnum = op.getopnum() - if op.has_no_side_effect() and op.result not in regalloc.longevity: + if op.has_no_side_effect() and op not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif not we_are_translated() and op.getopnum() == -124: + elif not we_are_translated() and op.getopnum() == -127: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) @@ -947,7 +947,7 @@ assert fcond is not None if op.is_guard(): regalloc.possibly_free_vars(op.getfailargs()) - if op.result: + if op.type != 'v': regalloc.possibly_free_var(op.result) regalloc.possibly_free_vars_for_op(op) regalloc.free_temp_vars() diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -49,6 +49,8 @@ def emit_op_int_add(self, op, arglocs, regalloc, fcond): return self.int_add_impl(op, arglocs, regalloc, fcond) + emit_op_nursery_ptr_increment = emit_op_int_add + def int_add_impl(self, op, arglocs, regalloc, fcond, flags=False): l0, l1, res = arglocs if flags: @@ -253,28 +255,102 @@ def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[3:], save_exc=False) + self._emit_guard(op, arglocs[2:], save_exc=False) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[3:], save_exc=False) + self._emit_guard(op, arglocs[2:], save_exc=False) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): - offset = locs[2] + offset = self.cpu.vtable_offset if offset is not None: - self.mc.LDR_ri(r.ip.value, locs[0].value, offset.value, cond=fcond) + self.mc.LDR_ri(r.ip.value, locs[0].value, offset, cond=fcond) self.mc.CMP_rr(r.ip.value, locs[1].value, cond=fcond) else: typeid = locs[1] - self.mc.LDRH_ri(r.ip.value, locs[0].value, cond=fcond) - if typeid.is_imm(): - self.mc.CMP_ri(r.ip.value, typeid.value, cond=fcond) - else: - self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond) + assert typeid.is_imm() + expected_typeid = (self.cpu.gc_ll_descr + .get_typeid_from_classptr_if_gcremovetypeptr(typeid.value)) + self._cmp_guard_gc_type(locs[0], expected_typeid, fcond) + + def _cmp_guard_gc_type(self, loc_ptr, expected_typeid, fcond=c.AL): + # Note that the typeid half-word is at offset 0 on a little-endian + # machine; it would be at offset 2 or 4 on a big-endian machine. + assert self.cpu.supports_guard_gc_type + assert 0 <= expected_typeid <= 0xFFFF + self.mc.LDRH_ri(r.ip.value, loc_ptr.value, 0, + cond=fcond) + xxxxxx #ENCODING NOT SUPPORTED HERE? + self.mc.SUB_ri(r.ip.value, r.ip.value, expected_typeid & 0xFF00, + cond=fcond) + self.mc.CMP_ri(r.ip.value, expected_typeid & 0xFF, + cond=fcond) + + def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): + self._cmp_guard_gc_type(arglocs[0], arglocs[1].value) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond + + def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): + assert self.cpu.supports_guard_gc_type + loc_object = arglocs[0] + loc_base_type_info = arglocs[1] + # idea: read the typeid, fetch one byte of the field 'infobits' from + # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + self.mc.LDRH_ri(r.ip.value, loc_object.value) + # + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + infobits_offset, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + + if shift_by > 0: + self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) + self.mc.LDRB_ri(r.ip.value, loc_base_type_info, r.ip.value) + self.mc.TST_ri(r.ip.value, imm=IS_OBJECT_FLAG) + self.guard_success_cc = c.NE + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond + + def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): + assert self.cpu.supports_guard_gc_type + loc_object = arglocs[0] + loc_check_against_class = arglocs[1] + loc_ofs_subclassrange_min = arglocs[2] + offset = self.cpu.vtable_offset + offset2 = self.cpu.subclassrange_min_offset + if offset is not None: + # read this field to get the vtable pointer + self.mc.LDR_ri(r.ip.value, loc_object.value, imm=offset) + # read the vtable's subclassrange_min field + self.mc.LDR_ri(r.ip.value, r.ip.value, imm=offset2) + else: + # read the typeid + self.mc.LDRH_ri(r.ip.value, loc_object.value) + # read the vtable's subclassrange_min field, as a single + # step with the correct offset + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + if shift_by > 0: + self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) + self.mc.LDR_ri(r.ip.value, loc_ofs_subclassrange_min.value, + r.ip.value) + # get the two bounds to check against + vtable_ptr = loc_check_against_class.getint() + vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) + check_min = vtable_ptr.subclassrange_min + check_max = vtable_ptr.subclassrange_max + # check by doing the unsigned comparison (tmp - min) < (max - min) + self.mc.SUB_ri(r.ip.value, r.ip.value, check_min) + self.mc.CMP_ri(r.ip.value, check_max - check_min) + # the guard passes if we get a result of "below" + self.guard_success_cc = c.LO + self.implement_guard(guard_token) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): return self._emit_guard(op, locs, save_exc=False, @@ -365,8 +441,12 @@ self.gen_func_epilog() return fcond - def emit_op_call(self, op, arglocs, regalloc, fcond): + def _genop_call(self, op, arglocs, regalloc, fcond): return self._emit_call(op, arglocs, fcond=fcond) + emit_op_call_i = _genop_call + emit_op_call_r = _genop_call + emit_op_call_f = _genop_call + emit_op_call_n = _genop_call def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): # args = [resloc, size, sign, args...] @@ -396,14 +476,17 @@ cb.emit() return fcond - def emit_op_same_as(self, op, arglocs, regalloc, fcond): + def _genop_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs if argloc is not resloc: self.mov_loc_loc(argloc, resloc) return fcond - emit_op_cast_ptr_to_int = emit_op_same_as - emit_op_cast_int_to_ptr = emit_op_same_as + emit_op_same_as_i = _genop_same_as + emit_op_same_as_r = _genop_same_as + emit_op_same_as_f = _genop_same_as + emit_op_cast_ptr_to_int = _genop_same_as + emit_op_cast_int_to_ptr = _genop_same_as def emit_op_guard_no_exception(self, op, arglocs, regalloc, fcond): loc = arglocs[0] @@ -574,7 +657,7 @@ emit_op_setfield_raw = emit_op_setfield_gc emit_op_zero_ptr_field = emit_op_setfield_gc - def emit_op_getfield_gc(self, op, arglocs, regalloc, fcond): + def _genop_getfield(self, op, arglocs, regalloc, fcond): base_loc, ofs, res, size = arglocs signed = op.getdescr().is_field_signed() scale = get_scale(size.value) @@ -592,7 +675,7 @@ self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond) return fcond - def emit_op_getinteriorfield_gc(self, op, arglocs, regalloc, fcond): + def _genop_interiorfield(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, res_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs scale = get_scale(fieldsize.value) @@ -613,6 +696,10 @@ imm(scale), signed, fcond) return fcond + emit_op_getinteriorfield_gc_i = _genop_getinteriorfield + emit_op_getinteriorfield_gc_r = _genop_getinteriorfield + emit_op_getinteriorfield_gc_f = _genop_getinteriorfield + def emit_op_setinteriorfield_gc(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, value_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs @@ -697,12 +784,13 @@ self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond) return fcond - def emit_op_getarrayitem_gc(self, op, arglocs, regalloc, fcond): + def _genop_getarrayitem(self, op, arglocs, regalloc, fcond): res_loc, base_loc, ofs_loc, scale, ofs = arglocs assert ofs_loc.is_core_reg() signed = op.getdescr().is_item_signed() # scale the offset as required + # XXX we should try to encode the scale inside the "shift" part of LDR if scale.value > 0: self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value) ofs_loc = r.ip @@ -714,6 +802,17 @@ self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond) return fcond + emit_op_getarrayitem_gc_i = _genop_getarrayitem + emit_op_getarrayitem_gc_r = _genop_getarrayitem + emit_op_getarrayitem_gc_f = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_i = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_r = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_f = _genop_getarrayitem + emit_op_getarrayitem_raw_i = _genop_getarrayitem + emit_op_getarrayitem_raw_f = _genop_getarrayitem + emit_op_getarrayitem_raw_pure_i = _genop_getarrayitem + emit_op_getarrayitem_raw_pure_f = _genop_getarrayitem + def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale, signed=False, fcond=c.AL): if scale.value == 3: @@ -771,10 +870,7 @@ else: assert 0 - emit_op_getarrayitem_raw = emit_op_getarrayitem_gc - emit_op_getarrayitem_gc_pure = emit_op_getarrayitem_gc - - def emit_op_raw_load(self, op, arglocs, regalloc, fcond): + def _genop_raw_load(self, op, arglocs, regalloc, fcond): res_loc, base_loc, ofs_loc, scale, ofs = arglocs assert ofs_loc.is_core_reg() # no base offset @@ -783,6 +879,9 @@ self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond) return fcond + emit_op_raw_load_i = _genop_raw_load + emit_op_raw_load_f = _genop_raw_load + def emit_op_strlen(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs if l1.is_imm(): @@ -952,7 +1051,7 @@ def imm(self, v): return imm(v) - def emit_op_call_assembler(self, op, arglocs, regalloc, fcond): + def _genop_call_assembler(self, op, arglocs, regalloc, fcond): if len(arglocs) == 4: [argloc, vloc, result_loc, tmploc] = arglocs else: @@ -961,6 +1060,10 @@ self._store_force_index(self._find_nearby_operation(+1)) self.call_assembler(op, argloc, vloc, result_loc, tmploc) return fcond + emit_op_call_assembler_i = _genop_call_assembler + emit_op_call_assembler_r = _genop_call_assembler + emit_op_call_assembler_f = _genop_call_assembler + emit_op_call_assembler_n = _genop_call_assembler def _call_assembler_emit_call(self, addr, argloc, resloc): ofs = self.saved_threadlocal_addr @@ -991,9 +1094,9 @@ return pos def _call_assembler_load_result(self, op, result_loc): - if op.result is not None: + if op.type != 'v': # load the return value from (tmploc, 0) - kind = op.result.type + kind = op.type descr = self.cpu.getarraydescr_for_frame(kind) if kind == FLOAT: ofs = self.cpu.unpack_arraydescr(descr) @@ -1041,15 +1144,23 @@ self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) return fcond - def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): + def _genop_call_may_force(self, op, arglocs, regalloc, fcond): self._store_force_index(self._find_nearby_operation(+1)) self._emit_call(op, arglocs, fcond=fcond) return fcond + emit_op_call_may_force_i = _genop_call_may_force + emit_op_call_may_force_r = _genop_call_may_force + emit_op_call_may_force_f = _genop_call_may_force + emit_op_call_may_force_n = _genop_call_may_force - def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond): + def _genop_call_release_gil(self, op, arglocs, regalloc, fcond): self._store_force_index(self._find_nearby_operation(+1)) self._emit_call(op, arglocs, is_call_release_gil=True) return fcond + emit_op_call_release_gil_i = _genop_call_release_gil + emit_op_call_release_gil_r = _genop_call_release_gil + emit_op_call_release_gil_f = _genop_call_release_gil + emit_op_call_release_gil_n = _genop_call_release_gil def _store_force_index(self, guard_op): assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -24,8 +24,7 @@ from rpython.jit.backend.arm.arch import WORD, JITFRAME_FIXED_SIZE from rpython.jit.codewriter import longlong from rpython.jit.metainterp.history import (Const, ConstInt, ConstFloat, - ConstPtr, BoxInt, - Box, BoxPtr, + ConstPtr, INT, REF, FLOAT) from rpython.jit.metainterp.history import TargetToken from rpython.jit.metainterp.resoperation import rop @@ -689,8 +688,8 @@ arg0 = ConstInt(rffi.cast(lltype.Signed, op.getarg(0).getint())) loc = self.make_sure_var_in_reg(arg0) loc1 = self.get_scratch_reg(INT, boxes) - if op.result in self.longevity: - resloc = self.force_allocate_reg(op.result, boxes) + if op in self.longevity: + resloc = self.force_allocate_reg(op, boxes) self.possibly_free_var(op.result) else: resloc = None @@ -706,55 +705,23 @@ return arglocs def prepare_op_guard_class(self, op, fcond): - return self._prepare_guard_class(op, fcond) - - prepare_op_guard_nonnull_class = prepare_op_guard_class - - def _prepare_guard_class(self, op, fcond): assert not isinstance(op.getarg(0), Const) boxes = op.getarglist() x = self.make_sure_var_in_reg(boxes[0], boxes) y_val = rffi.cast(lltype.Signed, op.getarg(1).getint()) - arglocs = [x, None, None] + arglocs = [x, imm(y_val)] offset = self.cpu.vtable_offset if offset is not None: y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, imm(y_val)) - - assert check_imm_arg(offset) - offset_loc = imm(offset) - + self.assembler.load(y, arglocs[1]) arglocs[1] = y - arglocs[2] = offset_loc - else: - # XXX hard-coded assumption: to go from an object to its class - # we use the following algorithm: - # - read the typeid from mem(locs[0]), i.e. at offset 0 - # - keep the lower 16 bits read there - # - multiply by 4 and use it as an offset in type_info_group - # - add 16 bytes, to go past the TYPE_INFO structure - classptr = y_val - # here, we have to go back from 'classptr' to the value expected - # from reading the 16 bits in the object header - from rpython.memory.gctypelayout import GCData - sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) - expected_typeid = classptr - sizeof_ti - type_info_group - expected_typeid >>= 2 - if check_imm_arg(expected_typeid): - arglocs[1] = imm(expected_typeid) - else: - y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, imm(expected_typeid)) - arglocs[1] = y return self._prepare_guard(op, arglocs) - return arglocs + prepare_op_guard_nonnull_class = prepare_op_guard_class def compute_hint_frame_locations(self, operations): # optimization only: fill in the 'hint_frame_locations' dictionary @@ -782,7 +749,7 @@ assert len(arglocs) == jump_op.numargs() for i in range(jump_op.numargs()): box = jump_op.getarg(i) - if isinstance(box, Box): + if not isinstance(box, Const): loc = arglocs[i] if loc is not None and loc.is_stack(): self.frame_manager.hint_frame_pos[box] = ( @@ -1115,7 +1082,7 @@ # for boehm, this function should never be called arraydescr = op.getdescr() length_box = op.getarg(2) - assert isinstance(length_box, BoxInt) # we cannot have a const here! + assert not isinstance(length_box, Const) # we cannot have a const here! # the result will be in r0 self.rm.force_allocate_reg(op.result, selected_reg=r.r0) # we need r1 as a temporary @@ -1194,14 +1161,14 @@ # of some guard position = self.rm.position for arg in inputargs: - assert isinstance(arg, Box) + assert not isinstance(arg, Const) if self.last_real_usage.get(arg, -1) <= position: self.force_spill_var(arg) # for i in range(len(inputargs)): arg = inputargs[i] - assert isinstance(arg, Box) + assert not isinstance(arg, Const) loc = self.loc(arg) arglocs[i] = loc if loc.is_core_reg() or loc.is_vfp_reg(): From noreply at buildbot.pypy.org Sun Sep 6 19:54:19 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 19:54:19 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: test and a fix Message-ID: <20150906175419.989C21C11C8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79481:6bc488bd103b Date: 2015-09-06 19:54 +0200 http://bitbucket.org/pypy/pypy/changeset/6bc488bd103b/ Log: test and a fix 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 @@ -560,6 +560,8 @@ self.propagate_bounds_backward(op.getarg(1)) def _propagate_int_is_true_or_zero(self, op, valnonzero, valzero): + if self.is_raw_ptr(op.getarg(0)): + return r = self.getintbound(op) if r.is_constant(): if r.getint() == valnonzero: 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 @@ -49,7 +49,7 @@ self.last_emitted_operation = op self.next_optimization.propagate_forward(op) - def getintbound(self, op):#, create=True): + def getintbound(self, op): assert op.type == 'i' op = self.get_box_replacement(op) if isinstance(op, ConstInt): @@ -75,13 +75,13 @@ op.set_forwarded(bound) def getnullness(self, op): - if op.type == 'i': - return self.getintbound(op).getnullness() - elif op.type == 'r': + if op.type == 'r' or self.is_raw_ptr(op): ptrinfo = self.getptrinfo(op) if ptrinfo is None: return info.INFO_UNKNOWN return ptrinfo.getnullness() + elif op.type == 'i': + return self.getintbound(op).getnullness() assert False def make_constant_class(self, op, class_const, update_last_guard=True): diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -504,7 +504,8 @@ self.emit_operation(op) def optimize_INT_IS_TRUE(self, op): - if self.getintbound(op.getarg(0)).is_bool(): + if (not self.is_raw_ptr(op.getarg(0)) and + self.getintbound(op.getarg(0)).is_bool()): self.make_equal_to(op, op.getarg(0)) return self._optimize_nullness(op, op.getarg(0), True) 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 @@ -8736,23 +8736,22 @@ """ self.optimize_loop(ops, ops) - def test_pass_both_short_preamble_and_arg(self): - ops = """ - [i0, i1] - i2 = int_add(i0, 1) - jump(i0, i2) - """ - expected = """ - [i0, i1, i2] - jump(i0, i2, i2) - """ - preamble = """ - [i0, i1] - i2 = int_add(i0, 1) - i3 = same_as(i2) - jump(i0, i2, i3) - """ - self.optimize_loop(ops, expected, preamble) + def test_raw_buffer_int_is_true(self): + ops = """ + [iinp] + i0 = call_i(123, 10, descr=raw_malloc_descr) + i1 = int_is_true(i0) + guard_true(i1) [] + i2 = int_is_zero(i0) + guard_false(i2) [] + jump(i0) + """ + expected = """ + [i2] + i0 = call_i(123, 10, descr=raw_malloc_descr) + jump(i0) + """ + self.optimize_loop(ops, expected) class TestLLtype(OptimizeOptTest, LLtypeMixin): From noreply at buildbot.pypy.org Sun Sep 6 21:25:06 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 21:25:06 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: port some of test_virtualstate Message-ID: <20150906192506.68A461C1358@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79482:ae007118e6b3 Date: 2015-09-06 21:25 +0200 http://bitbucket.org/pypy/pypy/changeset/ae007118e6b3/ Log: port some of test_virtualstate diff --git a/rpython/jit/metainterp/optimizeopt/TODO b/rpython/jit/metainterp/optimizeopt/TODO --- a/rpython/jit/metainterp/optimizeopt/TODO +++ b/rpython/jit/metainterp/optimizeopt/TODO @@ -3,3 +3,4 @@ * reenable cpu check (breaks --fork-before) * reenable jit iface * fix OS X, win, arm, 32bit +* reenable the int_add optimization diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -7,6 +7,7 @@ from rpython.jit.metainterp.history import ConstInt, ConstPtr from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\ InputArgFloat +from rpython.jit.backend.llgraph.runner import ArrayDescr from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper import rclass from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin, BaseTest, \ @@ -26,12 +27,20 @@ self.optearlyforce = None class BaseTestGenerateGuards(BaseTest): - def guards(self, info1, info2, box, opinfo, expected, inputargs=None): + def setup_class(self): + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + self.knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + self.knownclass_info2 = NotVirtualStateInfo(self.cpu, 'r', value) + + def guards(self, info1, info2, box, runtime_box, expected, inputargs=None): if inputargs is None: inputargs = [box] info1.position = info2.position = 0 state = GenerateGuardState(FakeOptimizer(self.cpu)) - info1.generate_guards(info2, box, opinfo, state) + info1.generate_guards(info2, box, runtime_box, state) self.compare(state.extra_guards, expected, inputargs) def compare(self, guards, expected, inputargs): @@ -445,59 +454,58 @@ def test_equal_inputargs(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) - value = info.InstancePtrInfo(classbox) + value = info.InstancePtrInfo(None, classbox) knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) vstate1 = VirtualState([knownclass_info, knownclass_info]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', None) vstate2 = VirtualState([unknown_info1, unknown_info1]) - assert vstate2.generalization_of(vstate2) - assert not vstate1.generalization_of(vstate2) - assert vstate2.generalization_of(vstate1) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', None) unknown_info2 = NotVirtualStateInfo(self.cpu, 'r', None) vstate3 = VirtualState([unknown_info1, unknown_info2]) - assert vstate3.generalization_of(vstate2) - assert vstate3.generalization_of(vstate1) - assert not vstate2.generalization_of(vstate3) - assert not vstate1.generalization_of(vstate3) + assert vstate3.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert vstate3.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate2.generalization_of(vstate3, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate3, FakeOptimizer(self.cpu)) expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ box = InputArgRef(self.nodeaddr) - state = vstate1.generate_guards(vstate2, [box, box], [None, None], - self.cpu) + state = vstate1.generate_guards(vstate2, [box, box], [box, box], + FakeOptimizer(self.cpu)) self.compare(state.extra_guards, expected, [box]) with py.test.raises(VirtualStatesCantMatch): vstate1.generate_guards(vstate3, [box, box], [None, None], - self.cpu) + FakeOptimizer(self.cpu)) with py.test.raises(VirtualStatesCantMatch): vstate2.generate_guards(vstate3, [box, box], [None, None], - self.cpu) + FakeOptimizer(self.cpu)) def test_generate_guards_on_virtual_fields_matches_array(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) - innervalue1 = info.InstancePtrInfo(classbox) + innervalue1 = info.InstancePtrInfo(None, classbox) innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) innerinfo1.position = 1 innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) innerinfo2.position = 1 - descr = object() - + descr = ArrayDescr(lltype.GcArray(llmemory.GCREF), self.cpu) info1 = VArrayStateInfo(descr) info1.fieldstate = [innerinfo1] info2 = VArrayStateInfo(descr) info2.fieldstate = [innerinfo2] - value1 = info.ArrayPtrInfo(descr, vdescr=descr, size=1) + value1 = info.ArrayPtrInfo(descr, size=1, is_virtual=True) box = InputArgRef(self.nodeaddr) value1._items[0] = box @@ -505,11 +513,16 @@ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ - self.guards(info1, info2, InputArgRef(), value1, expected, [box]) + array = lltype.malloc(lltype.GcArray(llmemory.GCREF), 1) + array[0] = self.nodeaddr + arrayaddr = lltype.cast_opaque_ptr(llmemory.GCREF, array) + runtime_box = InputArgRef(arrayaddr) + runtime_box._forwarded = value1 + self.guards(info1, info2, runtime_box, runtime_box, expected, [box]) def test_generate_guards_on_virtual_fields_matches_instance(self): classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) - innervalue1 = info.InstancePtrInfo(classbox) + innervalue1 = info.InstancePtrInfo(None, classbox) innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) innerinfo1.position = 1 innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) @@ -521,285 +534,280 @@ info2 = VirtualStateInfo(ConstInt(42), [self.nextdescr]) info2.fieldstate = [innerinfo2] - value1 = info.InstancePtrInfo(classbox, self.nodesize) + value1 = info.InstancePtrInfo(self.nodesize, classbox, is_virtual=True) nodebox = InputArgRef(self.nodeaddr) + node2box = InputArgRef(self.nodeaddr) value1._fields = [None] * (self.nextdescr.get_index() + 1) - value1._fields[self.nextdescr.get_index()] = nodebox + value1._fields[self.nextdescr.get_index()] = node2box expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ - self.guards(info1, info2, nodebox, value1, expected, [nodebox]) + runtime_box = InputArgRef(self.nodeaddr) + nodebox._forwarded = value1 + self.guards(info1, info2, nodebox, runtime_box, expected, [node2box]) def test_generate_guards_on_virtual_fields_matches_struct(self): - innervalue1 = PtrOptValue(self.nodebox) - constclassbox = self.cpu.ts.cls_of_box(self.nodebox) - innervalue1.make_constant_class(None, constclassbox) - innerinfo1 = NotVirtualStateInfo(innervalue1) + constclassbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + innervalue1 = info.InstancePtrInfo(None, constclassbox) + innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(PtrOptValue(self.nodebox)) + innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) innerinfo2.position = 1 - structdescr = object() + structdescr = self.nodesize - info1 = VStructStateInfo(structdescr, [1]) + info1 = VStructStateInfo(structdescr, [self.nextdescr]) info1.fieldstate = [innerinfo1] - info2 = VStructStateInfo(structdescr, [1]) + info2 = VStructStateInfo(structdescr, [self.nextdescr]) info2.fieldstate = [innerinfo2] - value1 = VStructValue(self.cpu, structdescr, self.nodebox) - value1._fields = {1: PtrOptValue(self.nodebox)} + node2box = InputArgRef(self.nodeaddr) + value1 = info.InstancePtrInfo(structdescr, None, is_virtual=True) + value1._fields = [None] * (self.nextdescr.get_index() + 1) + value1._fields[self.nextdescr.get_index()] = node2box expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ - self.guards(info1, info2, value1, expected, [self.nodebox]) + nodebox = InputArgRef(self.nodeaddr) + nodebox._forwarded = value1 + runtime_box = InputArgRef(self.nodeaddr) + self.guards(info1, info2, nodebox, runtime_box, expected, + [node2box]) def test_generate_guards_on_virtual_fields_matches_arraystruct(self): - innervalue1 = PtrOptValue(self.nodebox) - constclassbox = self.cpu.ts.cls_of_box(self.nodebox) - innervalue1.make_constant_class(None, constclassbox) - innerinfo1 = NotVirtualStateInfo(innervalue1) + constclassbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + innervalue1 = info.InstancePtrInfo(None, constclassbox) + innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) innerinfo1.position = 1 - innerinfo2 = NotVirtualStateInfo(PtrOptValue(self.nodebox)) + innerinfo2 = NotVirtualStateInfo(self.cpu, 'r', None) innerinfo2.position = 1 - arraydescr = object() - fielddescr = object() + NODE = lltype.Struct('NODE', ('x', llmemory.GCREF)) + ARRAY = lltype.GcArray(NODE) + descr = self.cpu.fielddescrof(NODE, 'x') + + arraydescr = self.cpu.arraydescrof(ARRAY) - info1 = VArrayStructStateInfo(arraydescr, [[fielddescr]]) + info1 = VArrayStructStateInfo(arraydescr, [descr], 1) info1.fieldstate = [innerinfo1] - info2 = VArrayStructStateInfo(arraydescr, [[fielddescr]]) + info2 = VArrayStructStateInfo(arraydescr, [descr], 1) info2.fieldstate = [innerinfo2] - value1 = VArrayStructValue(arraydescr, 1, self.nodebox) - value1._items[0][fielddescr] = PtrOptValue(self.nodebox) + node = lltype.malloc(ARRAY, 1) + node[0].x = self.nodeaddr + nodeaddr = lltype.cast_opaque_ptr(llmemory.GCREF, node) + node2box = InputArgRef(self.nodeaddr) + value1 = info.ArrayStructInfo(arraydescr, 1, is_virtual=True) + value1._items = [node2box] expected = """ [p0] guard_nonnull_class(p0, ConstClass(node_vtable)) [] """ - self.guards(info1, info2, value1, expected, [self.nodebox]) + nodebox = InputArgRef(self.nodeaddr) + nodebox._forwarded = value1 + runtime_box = InputArgRef(nodeaddr) + self.guards(info1, info2, nodebox, runtime_box, expected, + [node2box]) # _________________________________________________________________________ # the below tests don't really have anything to do with guard generation def test_virtuals_with_equal_fields(self): info1 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) - info1.fieldstate = [knownclass_info, knownclass_info] + info1.fieldstate = [self.knownclass_info, self.knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VirtualStateInfo(ConstInt(42), [1, 2]) - unknown_info1 = NotVirtualStateInfo(OptValue(self.nodebox)) + unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', + info.InstancePtrInfo()) info2.fieldstate = [unknown_info1, unknown_info1] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) - assert not vstate1.generalization_of(vstate2) - assert vstate2.generalization_of(vstate1) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) info3 = VirtualStateInfo(ConstInt(42), [1, 2]) - unknown_info1 = NotVirtualStateInfo(OptValue(self.nodebox)) - unknown_info2 = NotVirtualStateInfo(OptValue(self.nodebox)) + unknown_info1 = NotVirtualStateInfo(self.cpu, 'r', + info.InstancePtrInfo()) + unknown_info2 = NotVirtualStateInfo(self.cpu, 'r', + info.InstancePtrInfo()) info3.fieldstate = [unknown_info1, unknown_info2] vstate3 = VirtualState([info3]) - assert vstate3.generalization_of(vstate2) - assert vstate3.generalization_of(vstate1) - assert not vstate2.generalization_of(vstate3) - assert not vstate1.generalization_of(vstate3) + assert vstate3.generalization_of(vstate2, FakeOptimizer(self.cpu)) + assert vstate3.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate2.generalization_of(vstate3, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate3, FakeOptimizer(self.cpu)) def test_virtuals_with_nonmatching_fields(self): info1 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox2) - classbox = self.cpu.ts.cls_of_box(self.nodebox2) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_virtuals_with_nonmatching_descrs(self): info1 = VirtualStateInfo(ConstInt(42), [10, 20]) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox2) - classbox = self.cpu.ts.cls_of_box(self.nodebox2) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_virtuals_with_nonmatching_classes(self): info1 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VirtualStateInfo(ConstInt(7), [1, 2]) - value = PtrOptValue(self.nodebox2) - classbox = self.cpu.ts.cls_of_box(self.nodebox2) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_nonvirtual_is_not_virtual(self): info1 = VirtualStateInfo(ConstInt(42), [1, 2]) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) - info2 = NotVirtualStateInfo(value) + info2 = NotVirtualStateInfo(self.cpu, 'r', value) vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_arrays_with_nonmatching_fields(self): info1 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox2) - classbox = self.cpu.ts.cls_of_box(self.nodebox2) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info2.fieldstate = [knownclass_info, knownclass_info] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_arrays_of_different_sizes(self): info1 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info1.fieldstate = [knownclass_info, knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.node2addr)) + value = info.InstancePtrInfo(None, classbox) + knownclass_info = NotVirtualStateInfo(self.cpu, 'r', value) info2.fieldstate = [knownclass_info] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_arrays_with_nonmatching_types(self): info1 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) - info1.fieldstate = [knownclass_info, knownclass_info] + info1.fieldstate = [self.knownclass_info, self.knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) info2 = VArrayStateInfo(7) - value = PtrOptValue(self.nodebox2) - classbox = self.cpu.ts.cls_of_box(self.nodebox2) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) - info2.fieldstate = [knownclass_info, knownclass_info] + info2.fieldstate = [self.knownclass_info2, self.knownclass_info2] vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_nonvirtual_is_not_array(self): info1 = VArrayStateInfo(42) - value = PtrOptValue(self.nodebox) - classbox = self.cpu.ts.cls_of_box(self.nodebox) - value.make_constant_class(None, classbox) - knownclass_info = NotVirtualStateInfo(value) - info1.fieldstate = [knownclass_info, knownclass_info] + info1.fieldstate = [self.knownclass_info, self.knownclass_info] vstate1 = VirtualState([info1]) - assert vstate1.generalization_of(vstate1) + assert vstate1.generalization_of(vstate1, FakeOptimizer(self.cpu)) - info2 = NotVirtualStateInfo(value) - vstate2 = VirtualState([info2]) - assert vstate2.generalization_of(vstate2) + vstate2 = VirtualState([self.knownclass_info]) + assert vstate2.generalization_of(vstate2, FakeOptimizer(self.cpu)) - assert not vstate2.generalization_of(vstate1) - assert not vstate1.generalization_of(vstate2) + assert not vstate2.generalization_of(vstate1, FakeOptimizer(self.cpu)) + assert not vstate1.generalization_of(vstate2, FakeOptimizer(self.cpu)) def test_crash_varay_clear(self): - innervalue1 = PtrOptValue(self.nodebox) - constclassbox = self.cpu.ts.cls_of_box(self.nodebox) - innervalue1.make_constant_class(None, constclassbox) - innerinfo1 = NotVirtualStateInfo(innervalue1) + classbox = self.cpu.ts.cls_of_box(InputArgRef(self.nodeaddr)) + innervalue1 = info.InstancePtrInfo(None, classbox) + innerinfo1 = NotVirtualStateInfo(self.cpu, 'r', innervalue1) innerinfo1.position = 1 innerinfo1.position_in_notvirtuals = 0 - descr = object() + descr = self.cpu.arraydescrof(lltype.GcArray(llmemory.GCREF)) info1 = VArrayStateInfo(descr) info1.fieldstate = [innerinfo1] - constvalue = self.cpu.ts.CVAL_NULLREF - value1 = VArrayValue(descr, constvalue, 1, self.nodebox, clear=True) - value1._items[0] = constvalue - info1.enum_forced_boxes([None], value1, None) + value1 = info.ArrayPtrInfo(descr, + ConstPtr(lltype.nullptr(llmemory.GCREF.TO)), + 1, True, is_virtual=True) + value1._items[0] = ConstPtr(lltype.nullptr(llmemory.GCREF.TO)) + nodebox = InputArgRef() + nodebox._forwarded = value1 + info1.enum_forced_boxes([None], nodebox, FakeOptimizer(self.cpu)) class BaseTestBridges(BaseTest): enable_opts = "intbounds:rewrite:virtualize:string:pure:heap:unroll" @@ -830,16 +838,16 @@ bridge = self.parse(bridge, postprocess=self.postprocess) self.add_guard_future_condition(bridge) for loop in loops: - loop.preamble = self.unroll_and_optimize(loop) + loop.preamble = self.unroll_and_optimize(loop).preamble preamble = loops[0].preamble token = JitCellToken() token.target_tokens = [l.operations[0].getdescr() for l in [preamble] + loops] boxes = {} - for b in bridge.inputargs + [op.result for op in bridge.operations]: + for b in bridge.inputargs + [op for op in bridge.operations]: boxes[str(b)] = b - for b, v in boxvalues.items(): - boxes[b].value = v + #for b, v in boxvalues.items(): + # boxes[b].value = v bridge.operations[-1].setdescr(token) self._do_optimize_bridge(bridge, None) if bridge.operations[-1].getopnum() == rop.LABEL: @@ -864,7 +872,7 @@ def test_nonnull(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) jump(p0) """ bridge = """ From noreply at buildbot.pypy.org Sun Sep 6 21:26:33 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 21:26:33 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: "obvious" fixes to consider_guard_subclass Message-ID: <20150906192633.0629D1C1358@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79483:018656ee7125 Date: 2015-09-06 21:26 +0200 http://bitbucket.org/pypy/pypy/changeset/018656ee7125/ Log: "obvious" fixes to consider_guard_subclass diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -443,9 +443,9 @@ def consider_guard_subclass(self, op): x = self.make_sure_var_in_reg(op.getarg(0)) + tmp_box = TempVar() + z = self.rm.force_allocate_reg(tmp_box, [op.getarg(0)]) y = self.loc(op.getarg(1)) - tmp_box = TempVar() - z = self.rm.force_allocate_reg(tmp_box) self.rm.possibly_free_var(tmp_box) self.perform_guard(op, [x, y, z], None) From noreply at buildbot.pypy.org Sun Sep 6 21:27:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 21:27:43 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: arm: progress, some tests pass Message-ID: <20150906192743.493F51C1358@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79484:b582cd6228d6 Date: 2015-09-06 21:28 +0200 http://bitbucket.org/pypy/pypy/changeset/b582cd6228d6/ Log: arm: progress, some tests pass diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -948,7 +948,7 @@ if op.is_guard(): regalloc.possibly_free_vars(op.getfailargs()) if op.type != 'v': - regalloc.possibly_free_var(op.result) + regalloc.possibly_free_var(op) regalloc.possibly_free_vars_for_op(op) regalloc.free_temp_vars() regalloc._check_invariants() diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -43,7 +43,7 @@ l1 = self.make_sure_var_in_reg(a1, boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result, boxes) + res = self.force_allocate_reg(op, boxes) return [l0, l1, res] if name: f.__name__ = name @@ -53,7 +53,7 @@ loc1 = self.make_sure_var_in_reg(op.getarg(0)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_two_regs_op(self, op, fcond): @@ -61,7 +61,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, loc2, res] def prepare_float_cmp(self, op, fcond): @@ -69,7 +69,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [loc1, loc2, res] def prepare_op_by_helper_call(name): @@ -85,8 +85,8 @@ self.force_spill_var(a0) self.possibly_free_vars_for_op(op) self.free_temp_vars() - self.after_call(op.result) - self.possibly_free_var(op.result) + self.after_call(op) + self.possibly_free_var(op) return [] f.__name__ = name return f @@ -105,7 +105,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [l0, l1, res] def prepare_unary_cmp(self, op, fcond): @@ -114,5 +114,5 @@ assert isinstance(a0, Box) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -15,14 +15,14 @@ from rpython.jit.backend.arm.helper.regalloc import VMEM_imm_size from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout -from rpython.jit.backend.arm.regalloc import TempBox +from rpython.jit.backend.arm.regalloc import TempVar from rpython.jit.backend.arm.locations import imm, RawSPStackLocation from rpython.jit.backend.llsupport import symbolic from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.jit.backend.llsupport.descr import InteriorFieldDescr from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale -from rpython.jit.metainterp.history import (Box, AbstractFailDescr, ConstInt, +from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt, INT, FLOAT, REF) from rpython.jit.metainterp.history import TargetToken from rpython.jit.metainterp.resoperation import rop @@ -269,29 +269,23 @@ offset = self.cpu.vtable_offset if offset is not None: self.mc.LDR_ri(r.ip.value, locs[0].value, offset, cond=fcond) - self.mc.CMP_rr(r.ip.value, locs[1].value, cond=fcond) + self.mc.gen_load_int(r.lr.value, locs[1].value, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) else: - typeid = locs[1] - assert typeid.is_imm() expected_typeid = (self.cpu.gc_ll_descr - .get_typeid_from_classptr_if_gcremovetypeptr(typeid.value)) + .get_typeid_from_classptr_if_gcremovetypeptr(locs[1].value)) self._cmp_guard_gc_type(locs[0], expected_typeid, fcond) def _cmp_guard_gc_type(self, loc_ptr, expected_typeid, fcond=c.AL): # Note that the typeid half-word is at offset 0 on a little-endian # machine; it would be at offset 2 or 4 on a big-endian machine. assert self.cpu.supports_guard_gc_type - assert 0 <= expected_typeid <= 0xFFFF - self.mc.LDRH_ri(r.ip.value, loc_ptr.value, 0, - cond=fcond) - xxxxxx #ENCODING NOT SUPPORTED HERE? - self.mc.SUB_ri(r.ip.value, r.ip.value, expected_typeid & 0xFF00, - cond=fcond) - self.mc.CMP_ri(r.ip.value, expected_typeid & 0xFF, - cond=fcond) + self.mc.LDRH_ri(r.ip.value, loc_ptr.value, cond=fcond) + self.mc.gen_load_int(r.lr.value, expected_typeid, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): - self._cmp_guard_gc_type(arglocs[0], arglocs[1].value) + self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond) self.guard_success_cc = c.EQ self._emit_guard(op, arglocs[2:], save_exc=False) return fcond @@ -299,7 +293,6 @@ def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): assert self.cpu.supports_guard_gc_type loc_object = arglocs[0] - loc_base_type_info = arglocs[1] # idea: read the typeid, fetch one byte of the field 'infobits' from # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. self.mc.LDRH_ri(r.ip.value, loc_object.value) @@ -309,26 +302,26 @@ infobits_offset, IS_OBJECT_FLAG = ( self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + self.mc.gen_load_int(r.lr.value, base_type_info + infobits_offset) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDRB_ri(r.ip.value, loc_base_type_info, r.ip.value) - self.mc.TST_ri(r.ip.value, imm=IS_OBJECT_FLAG) + self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value) + self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff)) self.guard_success_cc = c.NE - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[1:], save_exc=False) return fcond def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): assert self.cpu.supports_guard_gc_type loc_object = arglocs[0] loc_check_against_class = arglocs[1] - loc_ofs_subclassrange_min = arglocs[2] offset = self.cpu.vtable_offset offset2 = self.cpu.subclassrange_min_offset if offset is not None: # read this field to get the vtable pointer - self.mc.LDR_ri(r.ip.value, loc_object.value, imm=offset) + self.mc.LDR_ri(r.ip.value, loc_object.value, offset) # read the vtable's subclassrange_min field - self.mc.LDR_ri(r.ip.value, r.ip.value, imm=offset2) + self.mc.LDR_ri(r.ip.value, r.ip.value, offset2) else: # read the typeid self.mc.LDRH_ri(r.ip.value, loc_object.value) @@ -336,20 +329,29 @@ # step with the correct offset base_type_info, shift_by, sizeof_ti = ( self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + + self.mc.gen_load_int(r.lr.value, + base_type_info + sizeof_ti + offset2) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDR_ri(r.ip.value, loc_ofs_subclassrange_min.value, - r.ip.value) + self.mc.LDR_rr(r.ip.value, r.ip.value, l.lr.value) # get the two bounds to check against vtable_ptr = loc_check_against_class.getint() vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) check_min = vtable_ptr.subclassrange_min check_max = vtable_ptr.subclassrange_max + assert check_max > check_min + check_diff = check_max - check_min - 1 # check by doing the unsigned comparison (tmp - min) < (max - min) - self.mc.SUB_ri(r.ip.value, r.ip.value, check_min) - self.mc.CMP_ri(r.ip.value, check_max - check_min) - # the guard passes if we get a result of "below" - self.guard_success_cc = c.LO + self.mc.gen_load_int(r.lr.value, check_min) + self.mc.SUB_rr(r.ip.value, r.ip.value, r.lr.value) + if check_diff <= 0xff: + self.mc.CMP_ri(r.ip.value, check_diff) + else: + self.mc.gen_load_int(r.lr.value, check_diff) + self.mc.CMP_rr(r.ip.value, r.lr.value) + # the guard passes if we get a result of "below or equal" + self.guard_success_cc = c.LS self.implement_guard(guard_token) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): @@ -664,9 +666,16 @@ self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond) return fcond - emit_op_getfield_raw = emit_op_getfield_gc - emit_op_getfield_raw_pure = emit_op_getfield_gc - emit_op_getfield_gc_pure = emit_op_getfield_gc + emit_op_getfield_gc_i = _genop_getfield + emit_op_getfield_gc_r = _genop_getfield + emit_op_getfield_gc_f = _genop_getfield + emit_op_getfield_gc_pure_i = _genop_getfield + emit_op_getfield_gc_pure_r = _genop_getfield + emit_op_getfield_gc_pure_f = _genop_getfield + emit_op_getfield_raw_i = _genop_getfield + emit_op_getfield_raw_f = _genop_getfield + emit_op_getfield_raw_pure_i = _genop_getfield + emit_op_getfield_raw_pure_f = _genop_getfield def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond): base_loc, value_loc = arglocs @@ -675,7 +684,7 @@ self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond) return fcond - def _genop_interiorfield(self, op, arglocs, regalloc, fcond): + def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, res_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs scale = get_scale(fieldsize.value) @@ -932,7 +941,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[0], args) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[2], args) assert args[0] is not args[1] # forbidden case of aliasing - srcaddr_box = TempBox() + srcaddr_box = TempVar() forbidden_vars = [args[1], args[3], args[4], srcaddr_box] srcaddr_loc = regalloc.rm.force_allocate_reg(srcaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc, @@ -941,7 +950,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[1], forbidden_vars) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[3], forbidden_vars) forbidden_vars = [args[4], srcaddr_box] - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc, is_unicode=is_unicode) @@ -950,7 +959,7 @@ length_loc = regalloc.loc(length_box) if is_unicode: forbidden_vars = [srcaddr_box, dstaddr_box] - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, forbidden_vars) scale = self._get_unicode_item_scale() if not length_loc.is_core_reg(): @@ -1176,7 +1185,7 @@ return regalloc.operations[regalloc.rm.position + delta] def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): - self.emit_op_call(op, arglocs, regalloc, fcond) + self._emit_call(op, arglocs, fcond=fcond) self.propagate_memoryerror_if_r0_is_null() self._alignment_check() return fcond @@ -1294,7 +1303,7 @@ # address that we will pass as first argument to memset(). # It can be in the same register as either one, but not in # args[2], because we're still needing the latter. - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, [args[2]]) if startindex >= 0: # a constant ofs = baseofs + startindex * itemsize @@ -1350,7 +1359,7 @@ # we need a register that is different from dstaddr_loc, # but which can be identical to length_loc (as usual, # only if the length_box is not used by future operations) - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, [dstaddr_box]) self.mc.gen_load_int(r.ip.value, itemsize) diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -224,6 +224,8 @@ return self.rm.call_result_location(v) def after_call(self, v): + if v.type == 'v': + return if v.type == FLOAT: return self.vfprm.after_call(v) else: @@ -433,9 +435,11 @@ locs = self._prepare_op_int_add(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] + prepare_op_nursery_ptr_increment = prepare_op_int_add + def _prepare_op_int_sub(self, op, fcond): a0, a1 = boxes = op.getarglist() imm_a0 = check_imm_box(a0) @@ -455,7 +459,7 @@ locs = self._prepare_op_int_sub(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] def prepare_op_int_mul(self, op, fcond): @@ -467,19 +471,19 @@ self.possibly_free_vars(boxes) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [reg1, reg2, res] def prepare_op_int_force_ge_zero(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) - resloc = self.force_allocate_reg(op.result, [op.getarg(0)]) + resloc = self.force_allocate_reg(op, [op.getarg(0)]) return [argloc, resloc] def prepare_op_int_signext(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) numbytes = op.getarg(1).getint() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, imm(numbytes), resloc] prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') @@ -522,7 +526,7 @@ prepare_op_int_neg = prepare_unary_op prepare_op_int_invert = prepare_unary_op - def prepare_op_call(self, op, fcond): + def _prepare_op_call(self, op, fcond): calldescr = op.getdescr() assert calldescr is not None effectinfo = calldescr.get_extra_info() @@ -553,6 +557,11 @@ # ... return self._prepare_call(op) + prepare_op_call_i = _prepare_op_call + prepare_op_call_r = _prepare_op_call + prepare_op_call_f = _prepare_op_call + prepare_op_call_n = _prepare_op_call + def _prepare_call(self, op, force_store=[], save_all_regs=False, first_arg_index=1): args = [None] * (op.numargs() + 3) @@ -583,9 +592,7 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(force_store, save_all_regs=save_all_regs) - resloc = None - if op.result: - resloc = self.after_call(op.result) + resloc = self.after_call(op) return resloc def prepare_op_call_malloc_gc(self, op, fcond): @@ -597,12 +604,12 @@ loc1 = self.make_sure_var_in_reg(op.getarg(2)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc0, loc1, res] def _prepare_llong_to_int(self, op, fcond): loc0 = self.make_sure_var_in_reg(op.getarg(1)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc0, res] def _prepare_threadlocalref_get(self, op, fcond): @@ -610,7 +617,7 @@ calldescr = op.getdescr() size_loc = imm(calldescr.get_result_size()) sign_loc = imm(calldescr.is_result_signed()) - res_loc = self.force_allocate_reg(op.result) + res_loc = self.force_allocate_reg(op) return [ofs_loc, size_loc, sign_loc, res_loc] def _prepare_guard(self, op, args=None): @@ -668,7 +675,6 @@ l1 = self.make_sure_var_in_reg(a1, boxes) else: l1 = self.convert_to_imm(a1) - assert op.result is None arglocs = self._prepare_guard(op, [l0, l1]) self.possibly_free_vars(op.getarglist()) self.possibly_free_vars(op.getfailargs()) @@ -690,7 +696,7 @@ loc1 = self.get_scratch_reg(INT, boxes) if op in self.longevity: resloc = self.force_allocate_reg(op, boxes) - self.possibly_free_var(op.result) + self.possibly_free_var(op) else: resloc = None pos_exc_value = imm(self.cpu.pos_exc_value()) @@ -709,19 +715,16 @@ boxes = op.getarglist() x = self.make_sure_var_in_reg(boxes[0], boxes) - y_val = rffi.cast(lltype.Signed, op.getarg(1).getint()) - - arglocs = [x, imm(y_val)] - - offset = self.cpu.vtable_offset - if offset is not None: - y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, arglocs[1]) - arglocs[1] = y - - return self._prepare_guard(op, arglocs) + y_val = rffi.cast(lltype.Signed, boxes[1].getint()) + return self._prepare_guard(op, [x, imm(y_val)]) prepare_op_guard_nonnull_class = prepare_op_guard_class + prepare_op_guard_gc_type = prepare_op_guard_class + prepare_op_guard_subclass = prepare_op_guard_class + + def prepare_op_guard_is_object(self, op, fcond): + loc_object = self.make_sure_var_in_reg(op.getarg(0)) + return self._prepare_guard(op, [loc_object]) def compute_hint_frame_locations(self, operations): # optimization only: fill in the 'hint_frame_locations' dictionary @@ -814,7 +817,7 @@ ofs = op.getarg(1).getint() return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD) - def prepare_op_getfield_gc(self, op, fcond): + def _prepare_op_getfield(self, op, fcond): a0 = op.getarg(0) ofs, size, sign = unpack_fielddescr(op.getdescr()) base_loc = self.make_sure_var_in_reg(a0) @@ -827,12 +830,19 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [base_loc, ofs_loc, res, imm(size)] - prepare_op_getfield_raw = prepare_op_getfield_gc - prepare_op_getfield_raw_pure = prepare_op_getfield_gc - prepare_op_getfield_gc_pure = prepare_op_getfield_gc + prepare_op_getfield_gc_i = _prepare_op_getfield + prepare_op_getfield_gc_r = _prepare_op_getfield + prepare_op_getfield_gc_f = _prepare_op_getfield + prepare_op_getfield_raw_i = _prepare_op_getfield + prepare_op_getfield_raw_f = _prepare_op_getfield + prepare_op_getfield_raw_pure_i = _prepare_op_getfield + prepare_op_getfield_raw_pure_f = _prepare_op_getfield + prepare_op_getfield_gc_pure_i = _prepare_op_getfield + prepare_op_getfield_gc_pure_r = _prepare_op_getfield + prepare_op_getfield_gc_pure_f = _prepare_op_getfield def prepare_op_increment_debug_counter(self, op, fcond): boxes = op.getarglist() @@ -842,7 +852,7 @@ self.free_temp_vars() return [base_loc, value_loc] - def prepare_op_getinteriorfield_gc(self, op, fcond): + def _prepare_op_getinteriorfield(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t args = op.getarglist() @@ -857,10 +867,14 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - result_loc = self.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op) return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs), imm(itemsize), imm(fieldsize)] + prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield + def prepare_op_setinteriorfield_gc(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t @@ -887,7 +901,7 @@ base_loc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [res, base_loc, imm(ofs)] def prepare_op_setarrayitem_gc(self, op, fcond): @@ -902,7 +916,7 @@ prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc prepare_op_raw_store = prepare_op_setarrayitem_gc - def prepare_op_getarrayitem_gc(self, op, fcond): + def _prepare_op_getarrayitem(self, op, fcond): boxes = op.getarglist() size, ofs, _ = unpack_arraydescr(op.getdescr()) scale = get_scale(size) @@ -910,14 +924,22 @@ ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) assert check_imm_arg(ofs) return [res, base_loc, ofs_loc, imm(scale), imm(ofs)] - prepare_op_getarrayitem_raw = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_raw_pure = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_gc_pure = prepare_op_getarrayitem_gc - prepare_op_raw_load = prepare_op_getarrayitem_gc + prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem + prepare_op_raw_load_i = _prepare_op_getarrayitem + prepare_op_raw_load_f = _prepare_op_getarrayitem def prepare_op_strlen(self, op, fcond): args = op.getarglist() @@ -934,8 +956,8 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [l0, l1, res] def prepare_op_strgetitem(self, op, fcond): @@ -951,7 +973,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.cpu.translate_support_code) @@ -985,7 +1007,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [l0, l1, res] def prepare_op_unicodegetitem(self, op, fcond): @@ -995,7 +1017,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.cpu.translate_support_code) @@ -1014,7 +1036,7 @@ return [value_loc, base_loc, ofs_loc, imm(scale), imm(basesize), imm(itemsize)] - def prepare_op_same_as(self, op, fcond): + def _prepare_op_same_as(self, op, fcond): arg = op.getarg(0) imm_arg = check_imm_box(arg) if imm_arg: @@ -1023,18 +1045,21 @@ argloc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, resloc] - prepare_op_cast_ptr_to_int = prepare_op_same_as - prepare_op_cast_int_to_ptr = prepare_op_same_as + prepare_op_cast_ptr_to_int = _prepare_op_same_as + prepare_op_cast_int_to_ptr = _prepare_op_same_as + prepare_op_same_as_i = _prepare_op_same_as + prepare_op_same_as_r = _prepare_op_same_as + prepare_op_same_as_f = _prepare_op_same_as def prepare_op_call_malloc_nursery(self, op, fcond): size_box = op.getarg(0) assert isinstance(size_box, ConstInt) size = size_box.getint() - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1058,7 +1083,7 @@ sizeloc = self.rm.make_sure_var_in_reg(size_box) self.rm.possibly_free_var(size_box) # - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1084,7 +1109,7 @@ length_box = op.getarg(2) assert not isinstance(length_box, Const) # we cannot have a const here! # the result will be in r0 - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # we need r1 as a temporary tmp_box = TempVar() self.rm.force_allocate_reg(tmp_box, selected_reg=r.r1) @@ -1111,7 +1136,6 @@ prepare_op_leave_portal_frame = void def prepare_op_cond_call_gc_wb(self, op, fcond): - assert op.result is None # we force all arguments in a reg because it will be needed anyway by # the following setfield_gc or setarrayitem_gc. It avoids loading it # twice from the memory. @@ -1127,7 +1151,6 @@ prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb def prepare_op_cond_call(self, op, fcond): - assert op.result is None assert 2 <= op.numargs() <= 4 + 2 tmpreg = self.get_scratch_reg(INT, selected_reg=r.r4) v = op.getarg(1) @@ -1145,8 +1168,7 @@ def prepare_op_force_token(self, op, fcond): # XXX for now we return a regular reg - res_loc = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res_loc = self.force_allocate_reg(op) return [res_loc] def prepare_op_label(self, op, fcond): @@ -1195,18 +1217,33 @@ self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value) self.possibly_free_vars(op.getfailargs()) - def prepare_op_call_may_force(self, op, fcond): + def _prepare_op_call_may_force(self, op, fcond): return self._prepare_call(op, save_all_regs=True) - def prepare_op_call_release_gil(self, op, fcond): + prepare_op_call_may_force_i = _prepare_op_call_may_force + prepare_op_call_may_force_r = _prepare_op_call_may_force + prepare_op_call_may_force_f = _prepare_op_call_may_force + prepare_op_call_may_force_n = _prepare_op_call_may_force + + def _prepare_op_call_release_gil(self, op, fcond): return self._prepare_call(op, save_all_regs=True, first_arg_index=2) - def prepare_op_call_assembler(self, op, fcond): + prepare_op_call_release_gil_i = _prepare_op_call_release_gil + prepare_op_call_release_gil_r = _prepare_op_call_release_gil + prepare_op_call_release_gil_f = _prepare_op_call_release_gil + prepare_op_call_release_gil_n = _prepare_op_call_release_gil + + def _prepare_op_call_assembler(self, op, fcond): locs = self.locs_for_call_assembler(op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) return locs + [resloc, tmploc] + prepare_op_call_assembler_i = _prepare_op_call_assembler + prepare_op_call_assembler_r = _prepare_op_call_assembler + prepare_op_call_assembler_f = _prepare_op_call_assembler + prepare_op_call_assembler_n = _prepare_op_call_assembler + def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr args = gc_ll_descr.args_for_new(new_args) @@ -1236,18 +1273,17 @@ loc = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc, res] def prepare_op_cast_float_to_int(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.rm.force_allocate_reg(op.result) + res = self.rm.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_int_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc1, res] def prepare_force_spill(self, op, fcond): @@ -1259,17 +1295,17 @@ #def prepare_op_read_timestamp(self, op, fcond): # loc = self.get_scratch_reg(INT) - # res = self.vfprm.force_allocate_reg(op.result) + # res = self.vfprm.force_allocate_reg(op) # return [loc, res] def prepare_op_cast_float_to_singlefloat(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_singlefloat_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -56,7 +56,7 @@ looptoken = JitCellToken() targettoken = TargetToken() operations = [ - ResOperation(rop.LABEL, inp, None, descr=targettoken), + ResOperation(rop.LABEL, inp, descr=targettoken), ResOperation(rop.INT_ADD, [inp[0], inp[1]]), ResOperation(rop.INT_ADD, [inp[2], inp[3]]), ResOperation(rop.INT_ADD, [inp[4], inp[5]]), @@ -103,7 +103,7 @@ lt2.outermost_jitdriver_sd = FakeJitDriverSD() loop1 = parse(''' [i0] - i1 = call_assembler(i0, descr=lt2) + i1 = call_assembler_i(i0, descr=lt2) guard_not_forced()[] finish(i1) ''', namespace=locals()) @@ -180,19 +180,19 @@ def test_float_field(self): if not self.cpu.supports_floats: py.test.skip('requires floats') + t_box, T_box, _ = self.alloc_instance(self.TFloat) floatdescr = self.cpu.fielddescrof(self.SFloat, 'float') - t_box, T_box = self.alloc_instance(self.TFloat) self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == 3.4 + assert longlong.getrealfloat(res) == 3.4 # self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == -3.6 + assert longlong.getrealfloat(res) == -3.6 def test_compile_loop_many_int_args(self): for numargs in range(2, 30): @@ -268,13 +268,13 @@ targettoken = TargetToken() ops = """ [i0, f3] - i2 = same_as(i0) # but forced to be in a register + i2 = same_as_i(i0) # but forced to be in a register force_spill(i2) force_spill(f3) f4 = float_add(f3, 5.0) label(f3, f4, descr=targettoken) force_spill(f3) - f5 = same_as(f3) # but forced to be in a register + f5 = same_as_f(f3) # but forced to be in a register finish(f5) """ faildescr = BasicFailDescr(2) @@ -283,8 +283,8 @@ info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) ops2 = """ [i0, f1] - i1 = same_as(i0) - f2 = same_as(f1) + i1 = same_as_i(i0) + f2 = same_as_f(f1) f3 = float_add(f1, 10.0) force_spill(f3) force_spill(i1) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1063,7 +1063,7 @@ consider_setarrayitem_raw = consider_setarrayitem_gc consider_raw_store = consider_setarrayitem_gc - def _consider_getfield_gc(self, op): + def _consider_getfield(self, op): ofs, size, sign = unpack_fielddescr(op.getdescr()) ofs_loc = imm(ofs) size_loc = imm(size) @@ -1076,22 +1076,22 @@ sign_loc = imm0 self.perform(op, [base_loc, ofs_loc, size_loc, sign_loc], result_loc) - consider_getfield_gc_i = _consider_getfield_gc - consider_getfield_gc_r = _consider_getfield_gc - consider_getfield_gc_f = _consider_getfield_gc - consider_getfield_raw_i = _consider_getfield_gc - consider_getfield_raw_f = _consider_getfield_gc - consider_getfield_raw_pure_i = _consider_getfield_gc - consider_getfield_raw_pure_f = _consider_getfield_gc - consider_getfield_gc_pure_i = _consider_getfield_gc - consider_getfield_gc_pure_r = _consider_getfield_gc - consider_getfield_gc_pure_f = _consider_getfield_gc + consider_getfield_gc_i = _consider_getfield + consider_getfield_gc_r = _consider_getfield + consider_getfield_gc_f = _consider_getfield + consider_getfield_raw_i = _consider_getfield + consider_getfield_raw_f = _consider_getfield + consider_getfield_raw_pure_i = _consider_getfield + consider_getfield_raw_pure_f = _consider_getfield + consider_getfield_gc_pure_i = _consider_getfield + consider_getfield_gc_pure_r = _consider_getfield + consider_getfield_gc_pure_f = _consider_getfield def consider_increment_debug_counter(self, op): base_loc = self.loc(op.getarg(0)) self.perform_discard(op, [base_loc]) - def _consider_getarrayitem_gc(self, op): + def _consider_getarrayitem(self, op): itemsize, ofs, sign = unpack_arraydescr(op.getdescr()) args = op.getarglist() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) @@ -1104,20 +1104,20 @@ self.perform(op, [base_loc, ofs_loc, imm(itemsize), imm(ofs), sign_loc], result_loc) - consider_getarrayitem_gc_i = _consider_getarrayitem_gc - consider_getarrayitem_gc_r = _consider_getarrayitem_gc - consider_getarrayitem_gc_f = _consider_getarrayitem_gc - consider_getarrayitem_raw_i = _consider_getarrayitem_gc - consider_getarrayitem_raw_f = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_i = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_r = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_f = _consider_getarrayitem_gc - consider_getarrayitem_raw_pure_i = _consider_getarrayitem_gc - consider_getarrayitem_raw_pure_f = _consider_getarrayitem_gc - consider_raw_load_i = _consider_getarrayitem_gc - consider_raw_load_f = _consider_getarrayitem_gc + consider_getarrayitem_gc_i = _consider_getarrayitem + consider_getarrayitem_gc_r = _consider_getarrayitem + consider_getarrayitem_gc_f = _consider_getarrayitem + consider_getarrayitem_raw_i = _consider_getarrayitem + consider_getarrayitem_raw_f = _consider_getarrayitem + consider_getarrayitem_gc_pure_i = _consider_getarrayitem + consider_getarrayitem_gc_pure_r = _consider_getarrayitem + consider_getarrayitem_gc_pure_f = _consider_getarrayitem + consider_getarrayitem_raw_pure_i = _consider_getarrayitem + consider_getarrayitem_raw_pure_f = _consider_getarrayitem + consider_raw_load_i = _consider_getarrayitem + consider_raw_load_f = _consider_getarrayitem - def _consider_getinteriorfield_gc(self, op): + def _consider_getinteriorfield(self, op): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = imm(t[0]), imm(t[1]), imm(t[2]), t[3] if sign: @@ -1145,9 +1145,9 @@ self.perform(op, [base_loc, ofs, itemsize, fieldsize, index_loc, temp_loc, sign_loc], result_loc) - consider_getinteriorfield_gc_i = _consider_getinteriorfield_gc - consider_getinteriorfield_gc_r = _consider_getinteriorfield_gc - consider_getinteriorfield_gc_f = _consider_getinteriorfield_gc + consider_getinteriorfield_gc_i = _consider_getinteriorfield + consider_getinteriorfield_gc_r = _consider_getinteriorfield + consider_getinteriorfield_gc_f = _consider_getinteriorfield def consider_int_is_true(self, op): # doesn't need arg to be in a register From noreply at buildbot.pypy.org Sun Sep 6 21:30:58 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 21:30:58 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: another "obvious" fix Message-ID: <20150906193058.B2DBD1C1453@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79485:937d2f6f9dbe Date: 2015-09-06 21:30 +0200 http://bitbucket.org/pypy/pypy/changeset/937d2f6f9dbe/ Log: another "obvious" fix diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -437,7 +437,7 @@ def consider_guard_is_object(self, op): x = self.make_sure_var_in_reg(op.getarg(0)) tmp_box = TempVar() - y = self.rm.force_allocate_reg(tmp_box) + y = self.rm.force_allocate_reg(tmp_box, [op.getarg(0)]) self.rm.possibly_free_var(tmp_box) self.perform_guard(op, [x, y], None) From noreply at buildbot.pypy.org Sun Sep 6 21:31:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 21:31:00 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150906193100.C4A3A1C1453@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79486:1c7cb11eb3da Date: 2015-09-06 21:31 +0200 http://bitbucket.org/pypy/pypy/changeset/1c7cb11eb3da/ Log: merge diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -948,7 +948,7 @@ if op.is_guard(): regalloc.possibly_free_vars(op.getfailargs()) if op.type != 'v': - regalloc.possibly_free_var(op.result) + regalloc.possibly_free_var(op) regalloc.possibly_free_vars_for_op(op) regalloc.free_temp_vars() regalloc._check_invariants() diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -43,7 +43,7 @@ l1 = self.make_sure_var_in_reg(a1, boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result, boxes) + res = self.force_allocate_reg(op, boxes) return [l0, l1, res] if name: f.__name__ = name @@ -53,7 +53,7 @@ loc1 = self.make_sure_var_in_reg(op.getarg(0)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_two_regs_op(self, op, fcond): @@ -61,7 +61,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, loc2, res] def prepare_float_cmp(self, op, fcond): @@ -69,7 +69,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [loc1, loc2, res] def prepare_op_by_helper_call(name): @@ -85,8 +85,8 @@ self.force_spill_var(a0) self.possibly_free_vars_for_op(op) self.free_temp_vars() - self.after_call(op.result) - self.possibly_free_var(op.result) + self.after_call(op) + self.possibly_free_var(op) return [] f.__name__ = name return f @@ -105,7 +105,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [l0, l1, res] def prepare_unary_cmp(self, op, fcond): @@ -114,5 +114,5 @@ assert isinstance(a0, Box) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -15,14 +15,14 @@ from rpython.jit.backend.arm.helper.regalloc import VMEM_imm_size from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout -from rpython.jit.backend.arm.regalloc import TempBox +from rpython.jit.backend.arm.regalloc import TempVar from rpython.jit.backend.arm.locations import imm, RawSPStackLocation from rpython.jit.backend.llsupport import symbolic from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.jit.backend.llsupport.descr import InteriorFieldDescr from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale -from rpython.jit.metainterp.history import (Box, AbstractFailDescr, ConstInt, +from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt, INT, FLOAT, REF) from rpython.jit.metainterp.history import TargetToken from rpython.jit.metainterp.resoperation import rop @@ -269,29 +269,23 @@ offset = self.cpu.vtable_offset if offset is not None: self.mc.LDR_ri(r.ip.value, locs[0].value, offset, cond=fcond) - self.mc.CMP_rr(r.ip.value, locs[1].value, cond=fcond) + self.mc.gen_load_int(r.lr.value, locs[1].value, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) else: - typeid = locs[1] - assert typeid.is_imm() expected_typeid = (self.cpu.gc_ll_descr - .get_typeid_from_classptr_if_gcremovetypeptr(typeid.value)) + .get_typeid_from_classptr_if_gcremovetypeptr(locs[1].value)) self._cmp_guard_gc_type(locs[0], expected_typeid, fcond) def _cmp_guard_gc_type(self, loc_ptr, expected_typeid, fcond=c.AL): # Note that the typeid half-word is at offset 0 on a little-endian # machine; it would be at offset 2 or 4 on a big-endian machine. assert self.cpu.supports_guard_gc_type - assert 0 <= expected_typeid <= 0xFFFF - self.mc.LDRH_ri(r.ip.value, loc_ptr.value, 0, - cond=fcond) - xxxxxx #ENCODING NOT SUPPORTED HERE? - self.mc.SUB_ri(r.ip.value, r.ip.value, expected_typeid & 0xFF00, - cond=fcond) - self.mc.CMP_ri(r.ip.value, expected_typeid & 0xFF, - cond=fcond) + self.mc.LDRH_ri(r.ip.value, loc_ptr.value, cond=fcond) + self.mc.gen_load_int(r.lr.value, expected_typeid, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): - self._cmp_guard_gc_type(arglocs[0], arglocs[1].value) + self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond) self.guard_success_cc = c.EQ self._emit_guard(op, arglocs[2:], save_exc=False) return fcond @@ -299,7 +293,6 @@ def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): assert self.cpu.supports_guard_gc_type loc_object = arglocs[0] - loc_base_type_info = arglocs[1] # idea: read the typeid, fetch one byte of the field 'infobits' from # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. self.mc.LDRH_ri(r.ip.value, loc_object.value) @@ -309,26 +302,26 @@ infobits_offset, IS_OBJECT_FLAG = ( self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + self.mc.gen_load_int(r.lr.value, base_type_info + infobits_offset) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDRB_ri(r.ip.value, loc_base_type_info, r.ip.value) - self.mc.TST_ri(r.ip.value, imm=IS_OBJECT_FLAG) + self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value) + self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff)) self.guard_success_cc = c.NE - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[1:], save_exc=False) return fcond def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): assert self.cpu.supports_guard_gc_type loc_object = arglocs[0] loc_check_against_class = arglocs[1] - loc_ofs_subclassrange_min = arglocs[2] offset = self.cpu.vtable_offset offset2 = self.cpu.subclassrange_min_offset if offset is not None: # read this field to get the vtable pointer - self.mc.LDR_ri(r.ip.value, loc_object.value, imm=offset) + self.mc.LDR_ri(r.ip.value, loc_object.value, offset) # read the vtable's subclassrange_min field - self.mc.LDR_ri(r.ip.value, r.ip.value, imm=offset2) + self.mc.LDR_ri(r.ip.value, r.ip.value, offset2) else: # read the typeid self.mc.LDRH_ri(r.ip.value, loc_object.value) @@ -336,20 +329,29 @@ # step with the correct offset base_type_info, shift_by, sizeof_ti = ( self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + + self.mc.gen_load_int(r.lr.value, + base_type_info + sizeof_ti + offset2) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDR_ri(r.ip.value, loc_ofs_subclassrange_min.value, - r.ip.value) + self.mc.LDR_rr(r.ip.value, r.ip.value, l.lr.value) # get the two bounds to check against vtable_ptr = loc_check_against_class.getint() vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) check_min = vtable_ptr.subclassrange_min check_max = vtable_ptr.subclassrange_max + assert check_max > check_min + check_diff = check_max - check_min - 1 # check by doing the unsigned comparison (tmp - min) < (max - min) - self.mc.SUB_ri(r.ip.value, r.ip.value, check_min) - self.mc.CMP_ri(r.ip.value, check_max - check_min) - # the guard passes if we get a result of "below" - self.guard_success_cc = c.LO + self.mc.gen_load_int(r.lr.value, check_min) + self.mc.SUB_rr(r.ip.value, r.ip.value, r.lr.value) + if check_diff <= 0xff: + self.mc.CMP_ri(r.ip.value, check_diff) + else: + self.mc.gen_load_int(r.lr.value, check_diff) + self.mc.CMP_rr(r.ip.value, r.lr.value) + # the guard passes if we get a result of "below or equal" + self.guard_success_cc = c.LS self.implement_guard(guard_token) def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): @@ -664,9 +666,16 @@ self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond) return fcond - emit_op_getfield_raw = emit_op_getfield_gc - emit_op_getfield_raw_pure = emit_op_getfield_gc - emit_op_getfield_gc_pure = emit_op_getfield_gc + emit_op_getfield_gc_i = _genop_getfield + emit_op_getfield_gc_r = _genop_getfield + emit_op_getfield_gc_f = _genop_getfield + emit_op_getfield_gc_pure_i = _genop_getfield + emit_op_getfield_gc_pure_r = _genop_getfield + emit_op_getfield_gc_pure_f = _genop_getfield + emit_op_getfield_raw_i = _genop_getfield + emit_op_getfield_raw_f = _genop_getfield + emit_op_getfield_raw_pure_i = _genop_getfield + emit_op_getfield_raw_pure_f = _genop_getfield def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond): base_loc, value_loc = arglocs @@ -675,7 +684,7 @@ self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond) return fcond - def _genop_interiorfield(self, op, arglocs, regalloc, fcond): + def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, res_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs scale = get_scale(fieldsize.value) @@ -932,7 +941,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[0], args) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[2], args) assert args[0] is not args[1] # forbidden case of aliasing - srcaddr_box = TempBox() + srcaddr_box = TempVar() forbidden_vars = [args[1], args[3], args[4], srcaddr_box] srcaddr_loc = regalloc.rm.force_allocate_reg(srcaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc, @@ -941,7 +950,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[1], forbidden_vars) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[3], forbidden_vars) forbidden_vars = [args[4], srcaddr_box] - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc, is_unicode=is_unicode) @@ -950,7 +959,7 @@ length_loc = regalloc.loc(length_box) if is_unicode: forbidden_vars = [srcaddr_box, dstaddr_box] - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, forbidden_vars) scale = self._get_unicode_item_scale() if not length_loc.is_core_reg(): @@ -1176,7 +1185,7 @@ return regalloc.operations[regalloc.rm.position + delta] def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): - self.emit_op_call(op, arglocs, regalloc, fcond) + self._emit_call(op, arglocs, fcond=fcond) self.propagate_memoryerror_if_r0_is_null() self._alignment_check() return fcond @@ -1294,7 +1303,7 @@ # address that we will pass as first argument to memset(). # It can be in the same register as either one, but not in # args[2], because we're still needing the latter. - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, [args[2]]) if startindex >= 0: # a constant ofs = baseofs + startindex * itemsize @@ -1350,7 +1359,7 @@ # we need a register that is different from dstaddr_loc, # but which can be identical to length_loc (as usual, # only if the length_box is not used by future operations) - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, [dstaddr_box]) self.mc.gen_load_int(r.ip.value, itemsize) diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -224,6 +224,8 @@ return self.rm.call_result_location(v) def after_call(self, v): + if v.type == 'v': + return if v.type == FLOAT: return self.vfprm.after_call(v) else: @@ -433,9 +435,11 @@ locs = self._prepare_op_int_add(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] + prepare_op_nursery_ptr_increment = prepare_op_int_add + def _prepare_op_int_sub(self, op, fcond): a0, a1 = boxes = op.getarglist() imm_a0 = check_imm_box(a0) @@ -455,7 +459,7 @@ locs = self._prepare_op_int_sub(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] def prepare_op_int_mul(self, op, fcond): @@ -467,19 +471,19 @@ self.possibly_free_vars(boxes) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [reg1, reg2, res] def prepare_op_int_force_ge_zero(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) - resloc = self.force_allocate_reg(op.result, [op.getarg(0)]) + resloc = self.force_allocate_reg(op, [op.getarg(0)]) return [argloc, resloc] def prepare_op_int_signext(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) numbytes = op.getarg(1).getint() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, imm(numbytes), resloc] prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') @@ -522,7 +526,7 @@ prepare_op_int_neg = prepare_unary_op prepare_op_int_invert = prepare_unary_op - def prepare_op_call(self, op, fcond): + def _prepare_op_call(self, op, fcond): calldescr = op.getdescr() assert calldescr is not None effectinfo = calldescr.get_extra_info() @@ -553,6 +557,11 @@ # ... return self._prepare_call(op) + prepare_op_call_i = _prepare_op_call + prepare_op_call_r = _prepare_op_call + prepare_op_call_f = _prepare_op_call + prepare_op_call_n = _prepare_op_call + def _prepare_call(self, op, force_store=[], save_all_regs=False, first_arg_index=1): args = [None] * (op.numargs() + 3) @@ -583,9 +592,7 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(force_store, save_all_regs=save_all_regs) - resloc = None - if op.result: - resloc = self.after_call(op.result) + resloc = self.after_call(op) return resloc def prepare_op_call_malloc_gc(self, op, fcond): @@ -597,12 +604,12 @@ loc1 = self.make_sure_var_in_reg(op.getarg(2)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc0, loc1, res] def _prepare_llong_to_int(self, op, fcond): loc0 = self.make_sure_var_in_reg(op.getarg(1)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc0, res] def _prepare_threadlocalref_get(self, op, fcond): @@ -610,7 +617,7 @@ calldescr = op.getdescr() size_loc = imm(calldescr.get_result_size()) sign_loc = imm(calldescr.is_result_signed()) - res_loc = self.force_allocate_reg(op.result) + res_loc = self.force_allocate_reg(op) return [ofs_loc, size_loc, sign_loc, res_loc] def _prepare_guard(self, op, args=None): @@ -668,7 +675,6 @@ l1 = self.make_sure_var_in_reg(a1, boxes) else: l1 = self.convert_to_imm(a1) - assert op.result is None arglocs = self._prepare_guard(op, [l0, l1]) self.possibly_free_vars(op.getarglist()) self.possibly_free_vars(op.getfailargs()) @@ -690,7 +696,7 @@ loc1 = self.get_scratch_reg(INT, boxes) if op in self.longevity: resloc = self.force_allocate_reg(op, boxes) - self.possibly_free_var(op.result) + self.possibly_free_var(op) else: resloc = None pos_exc_value = imm(self.cpu.pos_exc_value()) @@ -709,19 +715,16 @@ boxes = op.getarglist() x = self.make_sure_var_in_reg(boxes[0], boxes) - y_val = rffi.cast(lltype.Signed, op.getarg(1).getint()) - - arglocs = [x, imm(y_val)] - - offset = self.cpu.vtable_offset - if offset is not None: - y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, arglocs[1]) - arglocs[1] = y - - return self._prepare_guard(op, arglocs) + y_val = rffi.cast(lltype.Signed, boxes[1].getint()) + return self._prepare_guard(op, [x, imm(y_val)]) prepare_op_guard_nonnull_class = prepare_op_guard_class + prepare_op_guard_gc_type = prepare_op_guard_class + prepare_op_guard_subclass = prepare_op_guard_class + + def prepare_op_guard_is_object(self, op, fcond): + loc_object = self.make_sure_var_in_reg(op.getarg(0)) + return self._prepare_guard(op, [loc_object]) def compute_hint_frame_locations(self, operations): # optimization only: fill in the 'hint_frame_locations' dictionary @@ -814,7 +817,7 @@ ofs = op.getarg(1).getint() return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD) - def prepare_op_getfield_gc(self, op, fcond): + def _prepare_op_getfield(self, op, fcond): a0 = op.getarg(0) ofs, size, sign = unpack_fielddescr(op.getdescr()) base_loc = self.make_sure_var_in_reg(a0) @@ -827,12 +830,19 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [base_loc, ofs_loc, res, imm(size)] - prepare_op_getfield_raw = prepare_op_getfield_gc - prepare_op_getfield_raw_pure = prepare_op_getfield_gc - prepare_op_getfield_gc_pure = prepare_op_getfield_gc + prepare_op_getfield_gc_i = _prepare_op_getfield + prepare_op_getfield_gc_r = _prepare_op_getfield + prepare_op_getfield_gc_f = _prepare_op_getfield + prepare_op_getfield_raw_i = _prepare_op_getfield + prepare_op_getfield_raw_f = _prepare_op_getfield + prepare_op_getfield_raw_pure_i = _prepare_op_getfield + prepare_op_getfield_raw_pure_f = _prepare_op_getfield + prepare_op_getfield_gc_pure_i = _prepare_op_getfield + prepare_op_getfield_gc_pure_r = _prepare_op_getfield + prepare_op_getfield_gc_pure_f = _prepare_op_getfield def prepare_op_increment_debug_counter(self, op, fcond): boxes = op.getarglist() @@ -842,7 +852,7 @@ self.free_temp_vars() return [base_loc, value_loc] - def prepare_op_getinteriorfield_gc(self, op, fcond): + def _prepare_op_getinteriorfield(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t args = op.getarglist() @@ -857,10 +867,14 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - result_loc = self.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op) return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs), imm(itemsize), imm(fieldsize)] + prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield + def prepare_op_setinteriorfield_gc(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t @@ -887,7 +901,7 @@ base_loc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [res, base_loc, imm(ofs)] def prepare_op_setarrayitem_gc(self, op, fcond): @@ -902,7 +916,7 @@ prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc prepare_op_raw_store = prepare_op_setarrayitem_gc - def prepare_op_getarrayitem_gc(self, op, fcond): + def _prepare_op_getarrayitem(self, op, fcond): boxes = op.getarglist() size, ofs, _ = unpack_arraydescr(op.getdescr()) scale = get_scale(size) @@ -910,14 +924,22 @@ ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) assert check_imm_arg(ofs) return [res, base_loc, ofs_loc, imm(scale), imm(ofs)] - prepare_op_getarrayitem_raw = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_raw_pure = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_gc_pure = prepare_op_getarrayitem_gc - prepare_op_raw_load = prepare_op_getarrayitem_gc + prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem + prepare_op_raw_load_i = _prepare_op_getarrayitem + prepare_op_raw_load_f = _prepare_op_getarrayitem def prepare_op_strlen(self, op, fcond): args = op.getarglist() @@ -934,8 +956,8 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [l0, l1, res] def prepare_op_strgetitem(self, op, fcond): @@ -951,7 +973,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.cpu.translate_support_code) @@ -985,7 +1007,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [l0, l1, res] def prepare_op_unicodegetitem(self, op, fcond): @@ -995,7 +1017,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.cpu.translate_support_code) @@ -1014,7 +1036,7 @@ return [value_loc, base_loc, ofs_loc, imm(scale), imm(basesize), imm(itemsize)] - def prepare_op_same_as(self, op, fcond): + def _prepare_op_same_as(self, op, fcond): arg = op.getarg(0) imm_arg = check_imm_box(arg) if imm_arg: @@ -1023,18 +1045,21 @@ argloc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, resloc] - prepare_op_cast_ptr_to_int = prepare_op_same_as - prepare_op_cast_int_to_ptr = prepare_op_same_as + prepare_op_cast_ptr_to_int = _prepare_op_same_as + prepare_op_cast_int_to_ptr = _prepare_op_same_as + prepare_op_same_as_i = _prepare_op_same_as + prepare_op_same_as_r = _prepare_op_same_as + prepare_op_same_as_f = _prepare_op_same_as def prepare_op_call_malloc_nursery(self, op, fcond): size_box = op.getarg(0) assert isinstance(size_box, ConstInt) size = size_box.getint() - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1058,7 +1083,7 @@ sizeloc = self.rm.make_sure_var_in_reg(size_box) self.rm.possibly_free_var(size_box) # - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1084,7 +1109,7 @@ length_box = op.getarg(2) assert not isinstance(length_box, Const) # we cannot have a const here! # the result will be in r0 - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # we need r1 as a temporary tmp_box = TempVar() self.rm.force_allocate_reg(tmp_box, selected_reg=r.r1) @@ -1111,7 +1136,6 @@ prepare_op_leave_portal_frame = void def prepare_op_cond_call_gc_wb(self, op, fcond): - assert op.result is None # we force all arguments in a reg because it will be needed anyway by # the following setfield_gc or setarrayitem_gc. It avoids loading it # twice from the memory. @@ -1127,7 +1151,6 @@ prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb def prepare_op_cond_call(self, op, fcond): - assert op.result is None assert 2 <= op.numargs() <= 4 + 2 tmpreg = self.get_scratch_reg(INT, selected_reg=r.r4) v = op.getarg(1) @@ -1145,8 +1168,7 @@ def prepare_op_force_token(self, op, fcond): # XXX for now we return a regular reg - res_loc = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res_loc = self.force_allocate_reg(op) return [res_loc] def prepare_op_label(self, op, fcond): @@ -1195,18 +1217,33 @@ self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value) self.possibly_free_vars(op.getfailargs()) - def prepare_op_call_may_force(self, op, fcond): + def _prepare_op_call_may_force(self, op, fcond): return self._prepare_call(op, save_all_regs=True) - def prepare_op_call_release_gil(self, op, fcond): + prepare_op_call_may_force_i = _prepare_op_call_may_force + prepare_op_call_may_force_r = _prepare_op_call_may_force + prepare_op_call_may_force_f = _prepare_op_call_may_force + prepare_op_call_may_force_n = _prepare_op_call_may_force + + def _prepare_op_call_release_gil(self, op, fcond): return self._prepare_call(op, save_all_regs=True, first_arg_index=2) - def prepare_op_call_assembler(self, op, fcond): + prepare_op_call_release_gil_i = _prepare_op_call_release_gil + prepare_op_call_release_gil_r = _prepare_op_call_release_gil + prepare_op_call_release_gil_f = _prepare_op_call_release_gil + prepare_op_call_release_gil_n = _prepare_op_call_release_gil + + def _prepare_op_call_assembler(self, op, fcond): locs = self.locs_for_call_assembler(op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) return locs + [resloc, tmploc] + prepare_op_call_assembler_i = _prepare_op_call_assembler + prepare_op_call_assembler_r = _prepare_op_call_assembler + prepare_op_call_assembler_f = _prepare_op_call_assembler + prepare_op_call_assembler_n = _prepare_op_call_assembler + def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr args = gc_ll_descr.args_for_new(new_args) @@ -1236,18 +1273,17 @@ loc = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc, res] def prepare_op_cast_float_to_int(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.rm.force_allocate_reg(op.result) + res = self.rm.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_int_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc1, res] def prepare_force_spill(self, op, fcond): @@ -1259,17 +1295,17 @@ #def prepare_op_read_timestamp(self, op, fcond): # loc = self.get_scratch_reg(INT) - # res = self.vfprm.force_allocate_reg(op.result) + # res = self.vfprm.force_allocate_reg(op) # return [loc, res] def prepare_op_cast_float_to_singlefloat(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_singlefloat_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -56,7 +56,7 @@ looptoken = JitCellToken() targettoken = TargetToken() operations = [ - ResOperation(rop.LABEL, inp, None, descr=targettoken), + ResOperation(rop.LABEL, inp, descr=targettoken), ResOperation(rop.INT_ADD, [inp[0], inp[1]]), ResOperation(rop.INT_ADD, [inp[2], inp[3]]), ResOperation(rop.INT_ADD, [inp[4], inp[5]]), @@ -103,7 +103,7 @@ lt2.outermost_jitdriver_sd = FakeJitDriverSD() loop1 = parse(''' [i0] - i1 = call_assembler(i0, descr=lt2) + i1 = call_assembler_i(i0, descr=lt2) guard_not_forced()[] finish(i1) ''', namespace=locals()) @@ -180,19 +180,19 @@ def test_float_field(self): if not self.cpu.supports_floats: py.test.skip('requires floats') + t_box, T_box, _ = self.alloc_instance(self.TFloat) floatdescr = self.cpu.fielddescrof(self.SFloat, 'float') - t_box, T_box = self.alloc_instance(self.TFloat) self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == 3.4 + assert longlong.getrealfloat(res) == 3.4 # self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == -3.6 + assert longlong.getrealfloat(res) == -3.6 def test_compile_loop_many_int_args(self): for numargs in range(2, 30): @@ -268,13 +268,13 @@ targettoken = TargetToken() ops = """ [i0, f3] - i2 = same_as(i0) # but forced to be in a register + i2 = same_as_i(i0) # but forced to be in a register force_spill(i2) force_spill(f3) f4 = float_add(f3, 5.0) label(f3, f4, descr=targettoken) force_spill(f3) - f5 = same_as(f3) # but forced to be in a register + f5 = same_as_f(f3) # but forced to be in a register finish(f5) """ faildescr = BasicFailDescr(2) @@ -283,8 +283,8 @@ info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) ops2 = """ [i0, f1] - i1 = same_as(i0) - f2 = same_as(f1) + i1 = same_as_i(i0) + f2 = same_as_f(f1) f3 = float_add(f1, 10.0) force_spill(f3) force_spill(i1) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1063,7 +1063,7 @@ consider_setarrayitem_raw = consider_setarrayitem_gc consider_raw_store = consider_setarrayitem_gc - def _consider_getfield_gc(self, op): + def _consider_getfield(self, op): ofs, size, sign = unpack_fielddescr(op.getdescr()) ofs_loc = imm(ofs) size_loc = imm(size) @@ -1076,22 +1076,22 @@ sign_loc = imm0 self.perform(op, [base_loc, ofs_loc, size_loc, sign_loc], result_loc) - consider_getfield_gc_i = _consider_getfield_gc - consider_getfield_gc_r = _consider_getfield_gc - consider_getfield_gc_f = _consider_getfield_gc - consider_getfield_raw_i = _consider_getfield_gc - consider_getfield_raw_f = _consider_getfield_gc - consider_getfield_raw_pure_i = _consider_getfield_gc - consider_getfield_raw_pure_f = _consider_getfield_gc - consider_getfield_gc_pure_i = _consider_getfield_gc - consider_getfield_gc_pure_r = _consider_getfield_gc - consider_getfield_gc_pure_f = _consider_getfield_gc + consider_getfield_gc_i = _consider_getfield + consider_getfield_gc_r = _consider_getfield + consider_getfield_gc_f = _consider_getfield + consider_getfield_raw_i = _consider_getfield + consider_getfield_raw_f = _consider_getfield + consider_getfield_raw_pure_i = _consider_getfield + consider_getfield_raw_pure_f = _consider_getfield + consider_getfield_gc_pure_i = _consider_getfield + consider_getfield_gc_pure_r = _consider_getfield + consider_getfield_gc_pure_f = _consider_getfield def consider_increment_debug_counter(self, op): base_loc = self.loc(op.getarg(0)) self.perform_discard(op, [base_loc]) - def _consider_getarrayitem_gc(self, op): + def _consider_getarrayitem(self, op): itemsize, ofs, sign = unpack_arraydescr(op.getdescr()) args = op.getarglist() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) @@ -1104,20 +1104,20 @@ self.perform(op, [base_loc, ofs_loc, imm(itemsize), imm(ofs), sign_loc], result_loc) - consider_getarrayitem_gc_i = _consider_getarrayitem_gc - consider_getarrayitem_gc_r = _consider_getarrayitem_gc - consider_getarrayitem_gc_f = _consider_getarrayitem_gc - consider_getarrayitem_raw_i = _consider_getarrayitem_gc - consider_getarrayitem_raw_f = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_i = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_r = _consider_getarrayitem_gc - consider_getarrayitem_gc_pure_f = _consider_getarrayitem_gc - consider_getarrayitem_raw_pure_i = _consider_getarrayitem_gc - consider_getarrayitem_raw_pure_f = _consider_getarrayitem_gc - consider_raw_load_i = _consider_getarrayitem_gc - consider_raw_load_f = _consider_getarrayitem_gc + consider_getarrayitem_gc_i = _consider_getarrayitem + consider_getarrayitem_gc_r = _consider_getarrayitem + consider_getarrayitem_gc_f = _consider_getarrayitem + consider_getarrayitem_raw_i = _consider_getarrayitem + consider_getarrayitem_raw_f = _consider_getarrayitem + consider_getarrayitem_gc_pure_i = _consider_getarrayitem + consider_getarrayitem_gc_pure_r = _consider_getarrayitem + consider_getarrayitem_gc_pure_f = _consider_getarrayitem + consider_getarrayitem_raw_pure_i = _consider_getarrayitem + consider_getarrayitem_raw_pure_f = _consider_getarrayitem + consider_raw_load_i = _consider_getarrayitem + consider_raw_load_f = _consider_getarrayitem - def _consider_getinteriorfield_gc(self, op): + def _consider_getinteriorfield(self, op): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = imm(t[0]), imm(t[1]), imm(t[2]), t[3] if sign: @@ -1145,9 +1145,9 @@ self.perform(op, [base_loc, ofs, itemsize, fieldsize, index_loc, temp_loc, sign_loc], result_loc) - consider_getinteriorfield_gc_i = _consider_getinteriorfield_gc - consider_getinteriorfield_gc_r = _consider_getinteriorfield_gc - consider_getinteriorfield_gc_f = _consider_getinteriorfield_gc + consider_getinteriorfield_gc_i = _consider_getinteriorfield + consider_getinteriorfield_gc_r = _consider_getinteriorfield + consider_getinteriorfield_gc_f = _consider_getinteriorfield def consider_int_is_true(self, op): # doesn't need arg to be in a register From noreply at buildbot.pypy.org Sun Sep 6 21:39:09 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 21:39:09 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: arm: fixes Message-ID: <20150906193909.ADD731C0695@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79487:9fc1d9a8777c Date: 2015-09-06 21:39 +0200 http://bitbucket.org/pypy/pypy/changeset/9fc1d9a8777c/ Log: arm: fixes diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -50,7 +50,7 @@ helper = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None - if op.result: + if op.type != 'v': regs = r.caller_resp[1:] + [r.ip] else: regs = r.caller_resp diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -111,7 +111,7 @@ def prepare_unary_cmp(self, op, fcond): assert fcond is not None a0 = op.getarg(0) - assert isinstance(a0, Box) + assert not isinstance(a0, Const) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) res = self.force_allocate_reg_or_cc(op) From noreply at buildbot.pypy.org Sun Sep 6 21:43:54 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 6 Sep 2015 21:43:54 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: arm: fix and comment Message-ID: <20150906194354.D5E021C0FF6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79488:e660e97c1e8a Date: 2015-09-06 21:44 +0200 http://bitbucket.org/pypy/pypy/changeset/e660e97c1e8a/ Log: arm: fix and comment diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -1,13 +1,13 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r -from rpython.jit.metainterp.history import Const, FLOAT +from rpython.jit.metainterp.history import Const, ConstInt, FLOAT from rpython.rlib.objectmodel import we_are_translated VMEM_imm_size=0x3FC default_imm_size=0xFF def check_imm_arg(arg, size=default_imm_size, allow_zero=True): - assert not isinstance(arg, Const) + assert not isinstance(arg, Const) # because it must be an int :-) if not we_are_translated(): if not isinstance(arg, int): import pdb; pdb.set_trace() @@ -19,7 +19,7 @@ return i <= size and lower_bound def check_imm_box(arg, size=0xFF, allow_zero=True): - if isinstance(arg, Const): + if isinstance(arg, ConstInt): return check_imm_arg(arg.getint(), size, allow_zero) return False From noreply at buildbot.pypy.org Sun Sep 6 22:19:11 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 22:19:11 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: test and fix Message-ID: <20150906201911.6173E1C1E33@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79489:a77eb7711e99 Date: 2015-09-06 22:18 +0200 http://bitbucket.org/pypy/pypy/changeset/a77eb7711e99/ Log: test and fix 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 @@ -77,7 +77,11 @@ def make_guards(self, op, short, optimizer): pass - + + @specialize.arg(2) + def get_constant_string_spec(self, string_optimizer, mode): + return None # can't be constant + class NonNullPtrInfo(PtrInfo): _attrs_ = ('last_guard_pos',) last_guard_pos = -1 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 @@ -5873,7 +5873,16 @@ p1 = getfield_gc_i(p0, descr=otherdescr) finish(p1) """ - self.optimize_loop(ops, expected) + self.optimize_loop(ops, expected) + + def test_nonnull_str2unicode(self): + ops = """ + [p0] + guard_nonnull(p0) [] + p1 = call_r(0, p0, descr=s2u_descr) # string -> unicode + finish(p1) + """ + self.optimize_loop(ops, ops) class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Sun Sep 6 22:19:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 6 Sep 2015 22:19:13 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150906201913.70F861C1E33@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79490:922650aeb8e6 Date: 2015-09-06 22:19 +0200 http://bitbucket.org/pypy/pypy/changeset/922650aeb8e6/ Log: merge diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -50,7 +50,7 @@ helper = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None - if op.result: + if op.type != 'v': regs = r.caller_resp[1:] + [r.ip] else: regs = r.caller_resp diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -1,13 +1,13 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r -from rpython.jit.metainterp.history import Const, FLOAT +from rpython.jit.metainterp.history import Const, ConstInt, FLOAT from rpython.rlib.objectmodel import we_are_translated VMEM_imm_size=0x3FC default_imm_size=0xFF def check_imm_arg(arg, size=default_imm_size, allow_zero=True): - assert not isinstance(arg, Const) + assert not isinstance(arg, Const) # because it must be an int :-) if not we_are_translated(): if not isinstance(arg, int): import pdb; pdb.set_trace() @@ -19,7 +19,7 @@ return i <= size and lower_bound def check_imm_box(arg, size=0xFF, allow_zero=True): - if isinstance(arg, Const): + if isinstance(arg, ConstInt): return check_imm_arg(arg.getint(), size, allow_zero) return False @@ -111,7 +111,7 @@ def prepare_unary_cmp(self, op, fcond): assert fcond is not None a0 = op.getarg(0) - assert isinstance(a0, Box) + assert not isinstance(a0, Const) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) res = self.force_allocate_reg_or_cc(op) From noreply at buildbot.pypy.org Mon Sep 7 09:06:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 09:06:20 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: don't track nullity of raw pointers Message-ID: <20150907070620.24D331C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79491:19ec0c9ca54d Date: 2015-09-07 09:06 +0200 http://bitbucket.org/pypy/pypy/changeset/19ec0c9ca54d/ Log: don't track nullity of raw pointers 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 @@ -420,6 +420,9 @@ op = self.get_box_replacement(op) if op.is_constant(): return + if op.type == 'i': + # raw pointers + return opinfo = op.get_forwarded() if opinfo is not None: assert opinfo.is_nonnull() From noreply at buildbot.pypy.org Mon Sep 7 09:20:29 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 09:20:29 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: a fix for a crash, but not ideal things emitted Message-ID: <20150907072029.AEFC41C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79492:6054a6f8a5eb Date: 2015-09-07 09:20 +0200 http://bitbucket.org/pypy/pypy/changeset/6054a6f8a5eb/ Log: a fix for a crash, but not ideal things emitted 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 @@ -4255,6 +4255,32 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_str_concat_vstr2_str_2(self): + ops = """ + [i0, i1, p2] + p1 = newstr(2) + strsetitem(p1, 0, i0) + strsetitem(p1, 1, i1) + escape_n(p1) + p3 = call_r(0, p1, p2, descr=strconcatdescr) + jump(i1, i0, p3) + """ + expected = """ + [i0, i1, p2] + p1 = newstr(2) + strsetitem(p1, 0, i0) + strsetitem(p1, 1, i1) + escape_n(p1) + i2 = strlen(p2) + i3 = int_add(2, i2) + p3 = newstr(i3) + strsetitem(p3, 0, i0) + strsetitem(p3, 1, i1) + copystrcontent(p2, p3, 0, 2, i2) + jump(i1, i0, p3) + """ + self.optimize_strunicode_loop(ops, expected) + def test_str_concat_str_vstr2(self): ops = """ [i0, i1, p2] diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -187,11 +187,9 @@ def string_copy_parts(self, op, string_optimizer, targetbox, offsetbox, mode): - if not self.is_virtual(): - # and not self.is_completely_initialized(): - raise Exception("implement me") - return VAbstractStringValue.string_copy_parts( - self, string_optimizer, targetbox, offsetbox, mode) + if not self.is_virtual(): # and not self.is_completely_initialized(): + return StrPtrInfo.string_copy_parts(self, op, string_optimizer, + targetbox, offsetbox, mode) else: return self.initialize_forced_string(op, string_optimizer, targetbox, offsetbox, mode) From noreply at buildbot.pypy.org Mon Sep 7 09:22:09 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 09:22:09 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: whack Message-ID: <20150907072209.EB5781C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79493:7a568c7a6306 Date: 2015-09-07 09:22 +0200 http://bitbucket.org/pypy/pypy/changeset/7a568c7a6306/ Log: whack diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -102,7 +102,8 @@ newop.set_forwarded(self) op = optforce.get_box_replacement(op) op.set_forwarded(newop) - self.initialize_forced_string(op, optforce, op, CONST_0, self.mode) + optstring = optforce.optimizer.optstring + self.initialize_forced_string(op, optstring, op, CONST_0, self.mode) return newop def initialize_forced_string(self, op, string_optimizer, targetbox, @@ -344,7 +345,8 @@ # up to M characters are done "inline", i.e. with STRGETITEM/STRSETITEM # instead of just a COPYSTRCONTENT. for i in range(lgt.getint()): - charbox = _strgetitem(string_optimizer, srcbox, srcoffsetbox, mode) + charbox = string_optimizer.strgetitem(None, srcbox, srcoffsetbox, + mode) srcoffsetbox = _int_add(string_optimizer, srcoffsetbox, CONST_1) assert not isinstance(targetbox, Const)# ConstPtr never makes sense string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, From noreply at buildbot.pypy.org Mon Sep 7 09:37:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 09:37:12 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: be a bit more robust about missing fieldstate Message-ID: <20150907073712.39D311C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79494:91248376cc45 Date: 2015-09-07 09:37 +0200 http://bitbucket.org/pypy/pypy/changeset/91248376cc45/ Log: be a bit more robust about missing fieldstate diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -164,6 +164,8 @@ fieldbox = None fieldbox_runtime = None if self.fieldstate[i] is not None: + if other.fieldstate[i] is None: + raise VirtualStatesCantMatch self.fieldstate[i].generate_guards(other.fieldstate[i], fieldbox, fieldbox_runtime, state) @@ -244,7 +246,10 @@ fieldbox = opinfo._items[i] fieldbox_runtime = state.get_runtime_item(runtime_box, self.arraydescr, i) - self.fieldstate[i].generate_guards(other.fieldstate[i], + if self.fieldstate[i] is not None: + if other.fieldstate[i] is None: + raise VirtualStatesCantMatch + self.fieldstate[i].generate_guards(other.fieldstate[i], fieldbox, fieldbox_runtime, state) def enum_forced_boxes(self, boxes, box, optimizer, force_boxes=False): @@ -303,6 +308,8 @@ fieldstate = self.fieldstate[index] if fieldstate is None: continue + if other.fieldstate[index] is None: + raise VirtualStatesCantMatch if box is not None and opinfo is not None: fieldbox = opinfo._items[index] fieldbox_runtime = state.get_runtime_interiorfield( From noreply at buildbot.pypy.org Mon Sep 7 11:04:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 11:04:20 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: found the problem, failing test Message-ID: <20150907090420.6E9F81C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79495:9999d7fa9b54 Date: 2015-09-07 11:04 +0200 http://bitbucket.org/pypy/pypy/changeset/9999d7fa9b54/ Log: found the problem, failing test 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 @@ -4234,6 +4234,27 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_str_concat_2(self): + ops = """ + [p1, p2] + p3 = call_r(0, "fo", p1, descr=strconcatdescr) + escape_n(p3) + i5 = strgetitem(p3, 0) + escape_n(i5) + jump(p2, p3) + """ + expected = """ + [p1, p2] + i1 = strlen(p1) + i2 = strlen(p2) + i3 = int_add(i1, i2) + p3 = newstr(i3) + copystrcontent(p1, p3, 0, 0, i1) + copystrcontent(p2, p3, 0, i1, i2) + jump(p2, p3) + """ + self.optimize_strunicode_loop(ops, expected) + def test_str_concat_vstr2_str(self): ops = """ [i0, i1, p2] From noreply at buildbot.pypy.org Mon Sep 7 11:10:48 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 11:10:48 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: test and fix Message-ID: <20150907091048.81DF01C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79496:f0f6f371d27b Date: 2015-09-07 11:10 +0200 http://bitbucket.org/pypy/pypy/changeset/f0f6f371d27b/ Log: test and fix 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 @@ -4237,7 +4237,7 @@ def test_str_concat_2(self): ops = """ [p1, p2] - p3 = call_r(0, "fo", p1, descr=strconcatdescr) + p3 = call_r(0, s"fo", p1, descr=strconcatdescr) escape_n(p3) i5 = strgetitem(p3, 0) escape_n(i5) @@ -4246,12 +4246,14 @@ expected = """ [p1, p2] i1 = strlen(p1) - i2 = strlen(p2) - i3 = int_add(i1, i2) - p3 = newstr(i3) - copystrcontent(p1, p3, 0, 0, i1) - copystrcontent(p2, p3, 0, i1, i2) - jump(p2, p3) + i0 = int_add(2, i1) + p5 = newstr(i0) + strsetitem(p5, 0, 102) + strsetitem(p5, 1, 111) + copystrcontent(p1, p5, 0, 2, i1) + escape_n(p5) + escape_n(102) + jump(p2, p5) """ self.optimize_strunicode_loop(ops, expected) diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -393,10 +393,13 @@ if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) - return ConstInt(ord(s.chars[indexbox.getint()])) + resnewbox = ConstInt(ord(s.chars[indexbox.getint()])) else: s = strbox.getref(lltype.Ptr(rstr.UNICODE)) - return ConstInt(ord(s.chars[indexbox.getint()])) + resnewbox = ConstInt(ord(s.chars[indexbox.getint()])) + if resbox is not None: + string_optimizer.make_equal_to(resbox, resnewbox) + return resnewbox if resbox is None: resbox = ResOperation(mode.STRGETITEM, [strbox, indexbox]) else: From noreply at buildbot.pypy.org Mon Sep 7 11:37:57 2015 From: noreply at buildbot.pypy.org (vext01) Date: Mon, 7 Sep 2015 11:37:57 +0200 (CEST) Subject: [pypy-commit] pypy missing_openssl_include: Missing OpenSSL header. Message-ID: <20150907093757.3272D1C1358@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: missing_openssl_include Changeset: r79497:a03a6f117d43 Date: 2015-09-07 10:37 +0100 http://bitbucket.org/pypy/pypy/changeset/a03a6f117d43/ Log: Missing OpenSSL header. Fix for OpenBSD, already applied in ports: http://cvsweb.openbsd.org /cgi-bin/cvsweb/ports/lang/pypy/patches/patch- rpython_rlib_ropenssl_py?rev=1.5&content-type=text/x-cvsweb-markup diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -29,7 +29,8 @@ 'openssl/rand.h', 'openssl/evp.h', 'openssl/ossl_typ.h', - 'openssl/x509v3.h'] + 'openssl/x509v3.h', + 'openssl/comp.h'] eci = ExternalCompilationInfo( libraries = libraries, From noreply at buildbot.pypy.org Mon Sep 7 11:53:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 11:53:56 +0200 (CEST) Subject: [pypy-commit] pypy missing_openssl_include: Close branch missing_openssl_include Message-ID: <20150907095356.C485A1C0362@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: missing_openssl_include Changeset: r79498:f297be01a102 Date: 2015-09-07 11:54 +0200 http://bitbucket.org/pypy/pypy/changeset/f297be01a102/ Log: Close branch missing_openssl_include From noreply at buildbot.pypy.org Mon Sep 7 11:54:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 11:54:17 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged in missing_openssl_include (pull request #332) Message-ID: <20150907095417.779AF1C0362@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79499:3d4dfa75634c Date: 2015-09-07 11:54 +0200 http://bitbucket.org/pypy/pypy/changeset/3d4dfa75634c/ Log: Merged in missing_openssl_include (pull request #332) Missing OpenSSL header. diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -29,7 +29,8 @@ 'openssl/rand.h', 'openssl/evp.h', 'openssl/ossl_typ.h', - 'openssl/x509v3.h'] + 'openssl/x509v3.h', + 'openssl/comp.h'] eci = ExternalCompilationInfo( libraries = libraries, From noreply at buildbot.pypy.org Mon Sep 7 12:11:40 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 7 Sep 2015 12:11:40 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Add and test cpu.check_is_object() and cpu.get_actual_typeid(), Message-ID: <20150907101140.78C071C034D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79500:6da38340bd1a Date: 2015-09-07 12:11 +0200 http://bitbucket.org/pypy/pypy/changeset/6da38340bd1a/ Log: Add and test cpu.check_is_object() and cpu.get_actual_typeid(), to constant-fold guard_is_object and guard_gc_type. 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 @@ -517,6 +517,22 @@ self.descrs[key] = descr return descr + def check_is_object(self, gcptr): + """Check if the given, non-null gcptr refers to an rclass.OBJECT + or not at all (an unrelated GcStruct or a GcArray). Only usable + in the llgraph backend, or after translation of a real backend.""" + ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr()) + T = lltype.typeOf(ptr).TO + return heaptracker.has_gcstruct_a_vtable(T) or T is rclass.OBJECT + + def get_actual_typeid(self, gcptr): + """Fetch the actual typeid of the given gcptr, as an integer. + Only usable in the llgraph backend, or after translation of a + real backend. (Here in the llgraph backend, returns a + TypeIDSymbolic instead of a real integer.)""" + ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr()) + return TypeIDSymbolic(lltype.typeOf(ptr).TO) + # ------------------------------------------------------------ def maybe_on_top_of_llinterp(self, func, args, RESULT): diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -725,6 +725,24 @@ infobits_offset += self._infobits_offset_plus return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE) + def get_actual_typeid(self, gcptr): + # Read the whole GC header word. The typeid is the lower half-word. + hdr = rffi.cast(self.HDRPTR, gcptr) + type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid) + return llop.combine_ushort(lltype.Signed, type_id, 0) + + def check_is_object(self, gcptr): + # read the typeid, fetch one byte of the field 'infobits' from + # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + typeid = self.get_actual_typeid(gcptr) + # + base_type_info, shift_by, sizeof_ti = ( + self.get_translated_info_for_typeinfo()) + infobits_offset, IS_OBJECT_FLAG = ( + self.get_translated_info_for_guard_is_object()) + p = base_type_info + (typeid << shift_by) + infobits_offset + p = rffi.cast(rffi.CCHARP, p) + return (ord(p[0]) & IS_OBJECT_FLAG) != 0 # ____________________________________________________________ diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -480,8 +480,24 @@ descrs = self.gc_ll_descr.getframedescrs(self) base_ofs = self.unpack_arraydescr(descrs.arraydescr) return base_ofs + # ____________________________________________________________ + def check_is_object(self, gcptr): + """Check if the given, non-null gcptr refers to an rclass.OBJECT + or not at all (an unrelated GcStruct or a GcArray). Only usable + in the llgraph backend, or after translation of a real backend.""" + assert self.supports_guard_gc_type + return self.gc_ll_descr.check_is_object(gcptr) + + def get_actual_typeid(self, gcptr): + """Fetch the actual typeid of the given gcptr, as an integer. + Only usable in the llgraph backend, or after translation of a + real backend.""" + assert self.supports_guard_gc_type + return self.gc_ll_descr.get_actual_typeid(gcptr) + + # ____________________________________________________________ def bh_arraylen_gc(self, array, arraydescr): assert isinstance(arraydescr, ArrayDescr) diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py --- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py +++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py @@ -117,6 +117,11 @@ print 'fail' else: print '???' + # + if token is token2: # guard_gc_type + print int(cpu.get_actual_typeid(p0) == typeid_B) + if token is token3: # guard_is_object + print int(cpu.check_is_object(p0)) call_initial_function(t, g) @@ -129,14 +134,14 @@ 'match\n' 'fail\n' - 'fail\n' - 'match\n' - 'fail\n' - 'fail\n' + 'fail\n' '0\n' + 'match\n' '1\n' + 'fail\n' '0\n' + 'fail\n' '0\n' - 'match\n' - 'match\n' - 'fail\n' + 'match\n' '1\n' + 'match\n' '1\n' + 'fail\n' '0\n' 'fail\n' 'match\n' diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -4888,6 +4888,9 @@ c_typeid = ConstInt(descr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void') assert not self.guard_failed + # + got_typeid = self.cpu.get_actual_typeid(t_box.getref_base()) + assert got_typeid == c_typeid.getint() def test_passing_guard_gc_type_array(self): if not self.cpu.supports_guard_gc_type: @@ -4897,6 +4900,9 @@ c_typeid = ConstInt(arraydescr.get_type_id()) self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void') assert not self.guard_failed + # + got_typeid = self.cpu.get_actual_typeid(a_box.getref_base()) + assert got_typeid == c_typeid.getint() def test_failing_guard_gc_type(self): if not self.cpu.supports_guard_gc_type: @@ -4915,23 +4921,29 @@ ]: assert self.execute_operation(opname, args, 'void') == None assert self.guard_failed + # + got_typeid = self.cpu.get_actual_typeid(args[0].getref_base()) + assert got_typeid != args[1].getint() def test_guard_is_object(self): if not self.cpu.supports_guard_gc_type: py.test.skip("guard_gc_type not available") t_box, _, _ = self.alloc_instance(self.T) self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void') + assert not self.guard_failed + assert self.cpu.check_is_object(t_box.getref_base()) # - assert not self.guard_failed a_box, _ = self.alloc_array_of(rffi.SHORT, 342) self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void') assert self.guard_failed + assert not self.cpu.check_is_object(a_box.getref_base()) # S = lltype.GcStruct('S') s = lltype.malloc(S, immortal=True, zero=True) s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s)) self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void') assert self.guard_failed + assert not self.cpu.check_is_object(s_box.getref_base()) def test_guard_subclass(self): if not self.cpu.supports_guard_gc_type: From noreply at buildbot.pypy.org Mon Sep 7 12:20:59 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 12:20:59 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: kill mark_opaque_ptr Message-ID: <20150907102059.DC4F31C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79501:5ed69a741865 Date: 2015-09-07 12:21 +0200 http://bitbucket.org/pypy/pypy/changeset/5ed69a741865/ Log: kill mark_opaque_ptr 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 @@ -1106,10 +1106,6 @@ if self._is_gc(op.args[0]): return op - def rewrite_op_cast_opaque_ptr(self, op): - # None causes the result of this op to get aliased to op.args[0] - return [SpaceOperation('mark_opaque_ptr', op.args, None), None] - def rewrite_op_force_cast(self, op): v_arg = op.args[0] v_result = op.result diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -1328,19 +1328,6 @@ tr = Transformer(None, None) py.test.raises(NotImplementedError, tr.rewrite_operation, op) -def test_cast_opaque_ptr(): - S = lltype.GcStruct("S", ("x", lltype.Signed)) - v1 = varoftype(lltype.Ptr(S)) - v2 = varoftype(lltype.Ptr(rclass.OBJECT)) - - op = SpaceOperation('cast_opaque_ptr', [v1], v2) - tr = Transformer() - [op1, op2] = tr.rewrite_operation(op) - assert op1.opname == 'mark_opaque_ptr' - assert op1.args == [v1] - assert op1.result is None - assert op2 is None - def _test_threadlocalref_get(loop_inv): from rpython.rlib.rthread import ThreadLocalField tlfield = ThreadLocalField(lltype.Signed, 'foobar_test_', 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 @@ -532,9 +532,6 @@ ll_assert((i & 1) == 1, "bhimpl_cast_int_to_ptr: not an odd int") return lltype.cast_int_to_ptr(llmemory.GCREF, i) - @arguments("r") - def bhimpl_mark_opaque_ptr(a): - pass @arguments("r", "i") def bhimpl_record_exact_class(a, b): pass diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py --- a/rpython/jit/metainterp/heapcache.py +++ b/rpython/jit/metainterp/heapcache.py @@ -163,7 +163,7 @@ # its argument # XXX really? pass - # GETFIELD_GC, MARK_OPAQUE_PTR, PTR_EQ, and PTR_NE don't escape their + # GETFIELD_GC, PTR_EQ, and PTR_NE don't escape their # arguments elif (opnum != rop.GETFIELD_GC_R and opnum != rop.GETFIELD_GC_I and @@ -171,7 +171,6 @@ opnum != rop.GETFIELD_GC_PURE_R and opnum != rop.GETFIELD_GC_PURE_I and opnum != rop.GETFIELD_GC_PURE_F and - opnum != rop.MARK_OPAQUE_PTR and opnum != rop.PTR_EQ and opnum != rop.PTR_NE and opnum != rop.INSTANCE_PTR_EQ and diff --git a/rpython/jit/metainterp/optimizeopt/earlyforce.py b/rpython/jit/metainterp/optimizeopt/earlyforce.py --- a/rpython/jit/metainterp/optimizeopt/earlyforce.py +++ b/rpython/jit/metainterp/optimizeopt/earlyforce.py @@ -22,7 +22,6 @@ opnum != rop.SAME_AS_I and opnum != rop.SAME_AS_R and opnum != rop.SAME_AS_F and - opnum != rop.MARK_OPAQUE_PTR and not is_raw_free(op, opnum)): for arg in op.getarglist(): 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 @@ -746,10 +746,5 @@ optimize_SAME_AS_R = optimize_SAME_AS_I optimize_SAME_AS_F = optimize_SAME_AS_I - def optimize_MARK_OPAQUE_PTR(self, op): - #value = self.getvalue(op.getarg(0)) - #self.optimizer.opaque_pointers[value] = True - pass # XXX what do we do with that? - dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', default=Optimizer.optimize_default) 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 @@ -269,10 +269,6 @@ def opimpl_ptr_iszero(self, box): return self.execute(rop.PTR_EQ, box, history.CONST_NULL) - @arguments("box") - def opimpl_mark_opaque_ptr(self, box): - return self.execute(rop.MARK_OPAQUE_PTR, box) - @arguments("box", "box") def opimpl_record_exact_class(self, box, clsbox): from rpython.rtyper.lltypesystem import llmemory diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -770,7 +770,6 @@ '_MALLOC_LAST', 'FORCE_TOKEN/0/r', 'VIRTUAL_REF/2/r', # removed before it's passed to the backend - 'MARK_OPAQUE_PTR/1/n', # this one has no *visible* side effect, since the virtualizable # must be forced, however we need to execute it anyway '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations ----- From noreply at buildbot.pypy.org Mon Sep 7 12:31:34 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 12:31:34 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: a test and a fix for constant-folding away strange guards Message-ID: <20150907103134.F3E221C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79502:0798578f25bc Date: 2015-09-07 12:31 +0200 http://bitbucket.org/pypy/pypy/changeset/0798578f25bc/ Log: a test and a fix for constant-folding away strange guards diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -296,6 +296,13 @@ def optimize_GUARD_IS_OBJECT(self, op): info = self.getptrinfo(op.getarg(0)) + if info and info.is_constant(): + if info.is_null(): + raise InvalidLoop("A GUARD_IS_OBJECT(NULL) found") + c = self.get_box_replacement(op.getarg(0)) + if self.optimizer.cpu.check_is_object(c.getref_base()): + return + raise InvalidLoop("A GUARD_IS_OBJECT(not-an-object) found") if info is not None: if info.is_about_object(): return @@ -305,6 +312,12 @@ def optimize_GUARD_GC_TYPE(self, op): info = self.getptrinfo(op.getarg(0)) + if info and info.is_constant(): + c = self.get_box_replacement(op.getarg(0)) + tid = self.optimizer.cpu.get_actual_typeid(c.getref_base()) + if tid != op.getarg(1).getint(): + raise InvalidLoop("wrong GC type ID found on a constant") + return if info is not None and info.get_descr() is not None: if info.get_descr().get_type_id() != op.getarg(1).getint(): raise InvalidLoop("wrong GC types passed around!") @@ -327,6 +340,12 @@ def optimize_GUARD_SUBCLASS(self, op): info = self.getptrinfo(op.getarg(0)) + if info and info.is_constant(): + c = self.get_box_replacement(op.getarg(0)) + vtable = self.optimizer.cpu.ts.cls_of_box(c).getint() + if self._check_subclass(vtable, op.getarg(1).getint()): + return + raise InvalidLoop("GUARD_SUBCLASS(const) proven to always fail") if info is not None and info.is_about_object(): known_class = info.get_known_class(self.optimizer.cpu) if known_class: 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 @@ -5933,5 +5933,21 @@ """ self.optimize_loop(ops, ops) + def test_random_strange_guards_on_consts(self): + ops = """ + [p0] + guard_value(p0, ConstPtr(nodeaddr)) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + guard_gc_type(p0, ConstInt(node_tid)) [] + jump(p0) + """ + expected = """ + [p0] + guard_value(p0, ConstPtr(nodeaddr)) [] + jump(ConstPtr(nodeaddr)) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass 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 @@ -140,6 +140,7 @@ nullptr = lltype.nullptr(llmemory.GCREF.TO) #nodebox2 = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, node2)) nodesize = cpu.sizeof(NODE, node_vtable) + node_tid = nodesize.get_type_id() nodesize2 = cpu.sizeof(NODE2, node_vtable2) nodesize3 = cpu.sizeof(NODE3, node_vtable3) valuedescr = cpu.fielddescrof(NODE, 'value') From noreply at buildbot.pypy.org Mon Sep 7 12:36:19 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 12:36:19 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: remove cast_opaque_ptr Message-ID: <20150907103619.6252D1C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79503:81ec61519eeb Date: 2015-09-07 12:36 +0200 http://bitbucket.org/pypy/pypy/changeset/81ec61519eeb/ Log: remove cast_opaque_ptr 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 @@ -1106,6 +1106,10 @@ if self._is_gc(op.args[0]): return op + def rewrite_op_cast_opaque_ptr(self, op): + # None causes the result of this op to get aliased to op.args[0] + return None + def rewrite_op_force_cast(self, op): v_arg = op.args[0] v_result = op.result From noreply at buildbot.pypy.org Mon Sep 7 12:50:58 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 12:50:58 +0200 (CEST) Subject: [pypy-commit] benchmarks default: I don't think we ever want stdout to be share with the parent Message-ID: <20150907105058.0D87E1C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r334:fe2e89c0ae68 Date: 2015-09-07 12:51 +0200 http://bitbucket.org/pypy/benchmarks/changeset/fe2e89c0ae68/ Log: I don't think we ever want stdout to be share with the parent diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -158,7 +158,8 @@ logging.info('Running %s', ' '.join(args)) environ = os.environ.copy() environ['PYTHONPATH'] = relative('lib/pypy') - proc = subprocess.Popen(args, stderr=subprocess.PIPE, env=environ) + proc = subprocess.Popen(args, stderr=subprocess.PIPE, + stdout=subprocess.PIPE, env=environ) out, err = proc.communicate() retcode = proc.poll() if retcode != 0: From noreply at buildbot.pypy.org Mon Sep 7 19:26:35 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 19:26:35 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: support commented out lines Message-ID: <20150907172635.BB1621C0362@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79504:a001e4aa2eba Date: 2015-09-07 19:26 +0200 http://bitbucket.org/pypy/pypy/changeset/a001e4aa2eba/ Log: support commented out lines diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -383,6 +383,9 @@ return num, ops elif line.startswith(" "*(indent + 1)): raise ParseError("indentation not valid any more") + elif line.startswith(" " * indent + "#"): + num += 1 + continue else: line = line.strip() offset, line = self.parse_offset(line) From noreply at buildbot.pypy.org Mon Sep 7 19:29:54 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 7 Sep 2015 19:29:54 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: More tests for arraycopy, which sometimes does not invalidate the array copied to (3 of the 4 versions fail) Message-ID: <20150907172954.BB6C21C0362@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79505:40cc2e117d2a Date: 2015-09-07 19:30 +0200 http://bitbucket.org/pypy/pypy/changeset/40cc2e117d2a/ Log: More tests for arraycopy, which sometimes does not invalidate the array copied to (3 of the 4 versions fail) 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 @@ -3322,6 +3322,46 @@ ''' self.optimize_loop(ops, expected) + def test_arraycopy_invalidate_1(self): + ops = """ + [p0, i5] + p1 = new_array_clear(i5, descr=gcarraydescr) + call_n(0, p0, p1, 0, 0, i5, descr=arraycopydescr) + p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL + jump(p2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_2(self): + ops = """ + [p0, i5] + p1 = new_array_clear(i5, descr=gcarraydescr) + call_n(0, p0, p1, 0, 0, 3, descr=arraycopydescr) + p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL + jump(p2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_3(self): + ops = """ + [p0, i5] + p1 = new_array_clear(3, descr=gcarraydescr) + call_n(0, p0, p1, 0, 0, i5, descr=arraycopydescr) + p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL + jump(p2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_4(self): + ops = """ + [p0, i5] + p1 = new_array_clear(3, descr=gcarraydescr) + call_n(0, p0, p1, 0, 0, 3, descr=arraycopydescr) + p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL + jump(p2) + """ + self.optimize_loop(ops, ops) + def test_bound_lt(self): ops = """ [i0] From noreply at buildbot.pypy.org Mon Sep 7 19:42:12 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 7 Sep 2015 19:42:12 +0200 (CEST) Subject: [pypy-commit] pypy default: Add passing tests (from optresult-unroll) Message-ID: <20150907174212.8953F1C034D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79506:a53f57a9e951 Date: 2015-09-07 19:42 +0200 http://bitbucket.org/pypy/pypy/changeset/a53f57a9e951/ Log: Add passing tests (from optresult-unroll) 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 @@ -3287,6 +3287,50 @@ ''' self.optimize_loop(ops, expected) + def test_arraycopy_invalidate_1(self): + ops = """ + [i5] + p0 = escape() + p1 = new_array_clear(i5, descr=arraydescr) + call(0, p0, p1, 0, 0, i5, descr=arraycopydescr) + i2 = getarrayitem_gc(p1, 0, descr=arraydescr) # != NULL + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_2(self): + ops = """ + [i5] + p0 = escape() + p1 = new_array_clear(i5, descr=arraydescr) + call(0, p0, p1, 0, 0, 100, descr=arraycopydescr) + i2 = getarrayitem_gc(p1, 0, descr=arraydescr) # != NULL + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_3(self): + ops = """ + [i5] + p0 = escape() + p1 = new_array_clear(100, descr=arraydescr) + call(0, p0, p1, 0, 0, i5, descr=arraycopydescr) + i2 = getarrayitem_gc(p1, 0, descr=arraydescr) # != NULL + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_arraycopy_invalidate_4(self): + ops = """ + [i5] + p0 = escape() + p1 = new_array_clear(100, descr=arraydescr) + call(0, p0, p1, 0, 0, 100, descr=arraycopydescr) + i2 = getarrayitem_gc(p1, 0, descr=arraydescr) # != NULL + jump(i2) + """ + self.optimize_loop(ops, ops) + def test_bound_lt(self): ops = """ [i0] From noreply at buildbot.pypy.org Mon Sep 7 19:44:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 7 Sep 2015 19:44:24 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Fix the test. Now only versions 3 and 4 fail Message-ID: <20150907174424.523371C034D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79507:65b2fa912c67 Date: 2015-09-07 19:44 +0200 http://bitbucket.org/pypy/pypy/changeset/65b2fa912c67/ Log: Fix the test. Now only versions 3 and 4 fail 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 @@ -3324,41 +3324,45 @@ def test_arraycopy_invalidate_1(self): ops = """ - [p0, i5] - p1 = new_array_clear(i5, descr=gcarraydescr) + [i5] + p0 = escape_r() + p1 = new_array_clear(i5, descr=arraydescr) call_n(0, p0, p1, 0, 0, i5, descr=arraycopydescr) - p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL - jump(p2) + i2 = getarrayitem_gc_i(p1, 0, descr=arraydescr) # != NULL + jump(i2) """ self.optimize_loop(ops, ops) def test_arraycopy_invalidate_2(self): ops = """ - [p0, i5] - p1 = new_array_clear(i5, descr=gcarraydescr) - call_n(0, p0, p1, 0, 0, 3, descr=arraycopydescr) - p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL - jump(p2) + [i5] + p0 = escape_r() + p1 = new_array_clear(i5, descr=arraydescr) + call_n(0, p0, p1, 0, 0, 100, descr=arraycopydescr) + i2 = getarrayitem_gc_i(p1, 0, descr=arraydescr) # != NULL + jump(i2) """ self.optimize_loop(ops, ops) def test_arraycopy_invalidate_3(self): ops = """ - [p0, i5] - p1 = new_array_clear(3, descr=gcarraydescr) + [i5] + p0 = escape_r() + p1 = new_array_clear(100, descr=arraydescr) call_n(0, p0, p1, 0, 0, i5, descr=arraycopydescr) - p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL - jump(p2) + i2 = getarrayitem_gc_i(p1, 0, descr=arraydescr) # != NULL + jump(i2) """ self.optimize_loop(ops, ops) def test_arraycopy_invalidate_4(self): ops = """ - [p0, i5] - p1 = new_array_clear(3, descr=gcarraydescr) - call_n(0, p0, p1, 0, 0, 3, descr=arraycopydescr) - p2 = getarrayitem_gc_r(p1, 0, descr=gcarraydescr) # != NULL - jump(p2) + [i5] + p0 = escape_r() + p1 = new_array_clear(100, descr=arraydescr) + call_n(0, p0, p1, 0, 0, 100, descr=arraycopydescr) + i2 = getarrayitem_gc_i(p1, 0, descr=arraydescr) # != NULL + jump(i2) """ self.optimize_loop(ops, ops) From noreply at buildbot.pypy.org Mon Sep 7 20:28:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 20:28:54 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix Message-ID: <20150907182854.BEB011C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79508:f51560d30a95 Date: 2015-09-07 20:28 +0200 http://bitbucket.org/pypy/pypy/changeset/f51560d30a95/ Log: fix 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 @@ -501,6 +501,7 @@ for i in range(self.length): item = self._items[i] if item is None or self._clear and const.same_constant(item): + self._items[i] = None continue subbox = optforce.force_box(item) setop = ResOperation(rop.SETARRAYITEM_GC, From noreply at buildbot.pypy.org Mon Sep 7 20:32:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 20:32:56 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: rewrite it a bit, but we can likely do better Message-ID: <20150907183256.231A41C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79509:88f75fa26168 Date: 2015-09-07 20:33 +0200 http://bitbucket.org/pypy/pypy/changeset/88f75fa26168/ Log: rewrite it a bit, but we can likely do better 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 @@ -500,7 +500,10 @@ const = optforce.new_const_item(self.descr) for i in range(self.length): item = self._items[i] - if item is None or self._clear and const.same_constant(item): + if item is None: + continue + if self._clear and const.same_constant(item): + # clear the item so we don't know what's there self._items[i] = None continue subbox = optforce.force_box(item) From noreply at buildbot.pypy.org Mon Sep 7 22:56:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 22:56:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: make sure we don't compute stuff we don't need to Message-ID: <20150907205653.DF78A1C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79510:f6ed2160ac91 Date: 2015-09-07 21:47 +0200 http://bitbucket.org/pypy/pypy/changeset/f6ed2160ac91/ Log: make sure we don't compute stuff we don't need to diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -12,7 +12,8 @@ VirtualStateConstructor, VirtualStatesCantMatch) from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp from rpython.jit.metainterp import compile -from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.debug import debug_print, debug_start, debug_stop,\ + have_debug_prints class UnrollableOptimizer(Optimizer): def force_op_from_preamble(self, preamble_op): @@ -460,11 +461,12 @@ self.dump(memo) def dump(self, memo): - debug_start("jit-log-exported-state") - debug_print("[" + ", ".join([x.repr_short(memo) for x in self.next_iteration_args]) + "]") - for box in self.short_boxes: - debug_print(" " + box.repr(memo)) - debug_stop("jit-log-exported-state") + if have_debug_prints(): + debug_start("jit-log-exported-state") + debug_print("[" + ", ".join([x.repr_short(memo) for x in self.next_iteration_args]) + "]") + for box in self.short_boxes: + debug_print(" " + box.repr(memo)) + debug_stop("jit-log-exported-state") def final(self): return False From noreply at buildbot.pypy.org Mon Sep 7 22:56:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 22:56:56 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix test_virtualstate Message-ID: <20150907205656.0D5791C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79511:dee89540fdac Date: 2015-09-07 22:57 +0200 http://bitbucket.org/pypy/pypy/changeset/dee89540fdac/ Log: fix test_virtualstate 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 @@ -137,6 +137,9 @@ mynode2 = lltype.malloc(NODE) mynode2.parent.typeptr = node_vtable myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode2) + mynode3 = lltype.malloc(NODE2) + mynode3.parent.parent.typeptr = node_vtable2 + myptr3 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode3) nullptr = lltype.nullptr(llmemory.GCREF.TO) #nodebox2 = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, node2)) nodesize = cpu.sizeof(NODE, node_vtable) @@ -195,6 +198,7 @@ immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval') arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed)) + arraydescr_tid = arraydescr.get_type_id() array = lltype.malloc(lltype.GcArray(lltype.Signed), 15, zero=True) arrayref = lltype.cast_opaque_ptr(llmemory.GCREF, array) array2 = lltype.malloc(lltype.GcArray(lltype.Ptr(S)), 15, zero=True) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -4,7 +4,7 @@ VStructStateInfo, LEVEL_CONSTANT,\ VArrayStateInfo, NotVirtualStateInfo, VirtualState,\ GenerateGuardState, VirtualStatesCantMatch, VArrayStructStateInfo -from rpython.jit.metainterp.history import ConstInt, ConstPtr +from rpython.jit.metainterp.history import ConstInt, ConstPtr, TargetToken from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef,\ InputArgFloat from rpython.jit.backend.llgraph.runner import ArrayDescr @@ -18,7 +18,7 @@ from rpython.jit.metainterp.optimizeopt.test.test_optimizeopt import FakeMetaInterpStaticData from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp import resume +from rpython.jit.metainterp import resume, compile from rpython.jit.metainterp.optimizeopt import info class FakeOptimizer(Optimizer): @@ -810,7 +810,7 @@ info1.enum_forced_boxes([None], nodebox, FakeOptimizer(self.cpu)) class BaseTestBridges(BaseTest): - enable_opts = "intbounds:rewrite:virtualize:string:pure:heap:unroll" + enable_opts = "intbounds:rewrite:virtualize:string:pure:earlyforce:heap:unroll" def _do_optimize_bridge(self, bridge, call_pure_results): from rpython.jit.metainterp.optimizeopt import optimize_trace @@ -827,30 +827,50 @@ if hasattr(self, 'callinfocollection'): metainterp_sd.callinfocollection = self.callinfocollection # - optimize_trace(metainterp_sd, None, bridge, self.enable_opts) - + start_label = ResOperation(rop.LABEL, bridge.inputargs) + data = compile.BridgeCompileData(start_label, bridge.operations, + enable_opts=self.enable_opts, inline_short_preamble=True) + + info, newops = optimize_trace(metainterp_sd, None, data) + if info.final(): + bridge.operations = newops + bridge.inputargs = info.inputargs + return info - def optimize_bridge(self, loops, bridge, expected, expected_target='Loop', **boxvalues): + def optimize_bridge(self, loops, bridge, expected, expected_target='Loop', + boxvalues=None): if isinstance(loops, str): loops = (loops, ) loops = [self.parse(loop, postprocess=self.postprocess) for loop in loops] bridge = self.parse(bridge, postprocess=self.postprocess) self.add_guard_future_condition(bridge) + token = JitCellToken() + jump_args = bridge.operations[-1].getarglist() + if boxvalues is not None: + assert isinstance(boxvalues, list) + assert len(jump_args) == len(boxvalues) + for jump_arg, v in zip(jump_args, boxvalues): + jump_arg.setref_base(v) for loop in loops: - loop.preamble = self.unroll_and_optimize(loop).preamble + loop_jump_args = loop.operations[-1].getarglist() + if boxvalues is not None: + assert isinstance(boxvalues, list) + assert len(jump_args) == len(boxvalues) + for jump_arg, v in zip(loop_jump_args, boxvalues): + jump_arg.setref_base(v) + info = self.unroll_and_optimize(loop) + loop.preamble = info.preamble + loop.preamble.operations[0].setdescr(TargetToken(token)) preamble = loops[0].preamble - token = JitCellToken() token.target_tokens = [l.operations[0].getdescr() for l in [preamble] + loops] boxes = {} for b in bridge.inputargs + [op for op in bridge.operations]: boxes[str(b)] = b - #for b, v in boxvalues.items(): - # boxes[b].value = v bridge.operations[-1].setdescr(token) - self._do_optimize_bridge(bridge, None) - if bridge.operations[-1].getopnum() == rop.LABEL: + info = self._do_optimize_bridge(bridge, None) + if not info.final(): assert expected == 'RETRACE' return @@ -882,19 +902,22 @@ expected = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) jump(p0) """ - self.optimize_bridge(loop, bridge, 'RETRACE', p0=self.nullptr) - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) - self.optimize_bridge(loop, expected, expected, p0=self.myptr) - self.optimize_bridge(loop, expected, expected, p0=self.nullptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr]) + self.optimize_bridge(loop, expected, expected, 'Loop', [self.myptr]) + self.optimize_bridge(loop, expected, expected, 'Loop', [self.nullptr]) + self.optimize_bridge(loop, bridge, 'RETRACE', 'Loop', [self.nullptr]) def test_cached_nonnull(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] - call(p1, descr=nonwritedescr) + call_n(p1, descr=nonwritedescr) jump(p0) """ bridge = """ @@ -904,16 +927,18 @@ expected = """ [p0] guard_nonnull(p0) [] - p1 = getfield_gc(p0, descr=nextdescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] jump(p0, p1) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, boxvalues=[self.myptr]) def test_cached_unused_nonnull(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] jump(p0) """ @@ -924,31 +949,34 @@ expected = """ [p0] guard_nonnull(p0) [] - p1 = getfield_gc(p0, descr=nextdescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] jump(p0) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, boxvalues=[self.myptr]) def test_cached_invalid_nonnull(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] jump(p0) """ bridge = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_value(p1, ConstPtr(nullptr)) [] jump(p0) """ - self.optimize_bridge(loop, bridge, bridge, 'Preamble', p0=self.myptr) + self.optimize_bridge(loop, bridge, bridge, 'Preamble', + boxvalues=[self.myptr]) def test_multiple_nonnull(self): loops = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) jump(p0) """, """ [p0] @@ -962,22 +990,25 @@ [p0] jump(p0) """ - self.optimize_bridge(loops, bridge, expected, 'Loop1', p0=self.nullptr) + self.optimize_bridge(loops, bridge, expected, 'Loop1', [self.nullptr]) expected = """ [p0] guard_nonnull(p0) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) jump(p0) """ - self.optimize_bridge(loops, bridge, expected, 'Loop0', p0=self.myptr) + self.optimize_bridge(loops, bridge, expected, 'Loop0', [self.myptr]) def test_constant(self): loops = """ [i0] - i1 = same_as(1) + i1 = same_as_i(1) jump(i1) """, """ [i0] - i1 = same_as(2) + i1 = same_as_i(2) jump(i1) """, """ [i0] @@ -998,7 +1029,7 @@ def test_cached_constant(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_value(p1, ConstPtr(myptr)) [] jump(p0) """ @@ -1009,23 +1040,25 @@ expected = """ [p0] guard_nonnull(p0) [] - p1 = getfield_gc(p0, descr=nextdescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) guard_value(p1, ConstPtr(myptr)) [] jump(p0) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr]) def test_simple_virtual(self): loops = """ [p0, p1] - p2 = new_with_vtable(ConstClass(node_vtable)) + p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p1, descr=nextdescr) setfield_gc(p2, 7, descr=adescr) setfield_gc(p2, 42, descr=bdescr) jump(p2, p1) """,""" [p0, p1] - p2 = new_with_vtable(ConstClass(node_vtable)) + p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p1, descr=nextdescr) setfield_gc(p2, 9, descr=adescr) jump(p2, p1) @@ -1034,25 +1067,26 @@ [p0, p1] jump(p1) """ - self.optimize_bridge(loops, loops[0], expected, 'Loop0') - self.optimize_bridge(loops, loops[1], expected, 'Loop1') + ptr0 = lltype.malloc(self.NODE, zero=True) + self.optimize_bridge(loops, loops[0], expected, 'Loop0', [ptr0, None]) + self.optimize_bridge(loops, loops[1], expected, 'Loop1', [ptr0, None]) bridge = """ [p0, p1] - p2 = new_with_vtable(ConstClass(node_vtable)) + p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p1, descr=nextdescr) setfield_gc(p2, 42, descr=adescr) setfield_gc(p2, 7, descr=bdescr) jump(p2, p1) """ - self.optimize_bridge(loops, bridge, "RETRACE") + self.optimize_bridge(loops, bridge, "RETRACE", None, [ptr0, None]) bridge = """ [p0, p1] - p2 = new_with_vtable(ConstClass(node_vtable)) + p2 = new_with_vtable(descr=nodesize) setfield_gc(p2, p1, descr=nextdescr) setfield_gc(p2, 7, descr=adescr) jump(p2, p1) """ - self.optimize_bridge(loops, bridge, "RETRACE") + self.optimize_bridge(loops, bridge, "RETRACE", None, [ptr0, None]) def test_known_class(self): loops = """ @@ -1068,16 +1102,16 @@ [p0] jump(p0) """ - self.optimize_bridge(loops, bridge, loops[0], 'Loop0', p0=self.nodebox.value) - self.optimize_bridge(loops, bridge, loops[1], 'Loop1', p0=self.nodebox2.value) - self.optimize_bridge(loops[0], bridge, 'RETRACE', p0=self.nodebox2.value) - self.optimize_bridge(loops, loops[0], loops[0], 'Loop0', p0=self.nullptr) - self.optimize_bridge(loops, loops[1], loops[1], 'Loop1', p0=self.nullptr) + self.optimize_bridge(loops, bridge, loops[0], 'Loop0', [self.myptr]) + self.optimize_bridge(loops, bridge, loops[1], 'Loop1', [self.myptr3]) + self.optimize_bridge(loops[0], bridge, 'RETRACE', [self.myptr3]) + self.optimize_bridge(loops, loops[0], loops[0], 'Loop0', [self.nullptr]) + self.optimize_bridge(loops, loops[1], loops[1], 'Loop1', [self.nullptr]) def test_cached_known_class(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) + p1 = getfield_gc_r(p0, descr=nextdescr) guard_class(p1, ConstClass(node_vtable)) [] jump(p0) """ @@ -1088,42 +1122,48 @@ expected = """ [p0] guard_nonnull(p0) [] - p1 = getfield_gc(p0, descr=nextdescr) - guard_nonnull_class(p1, ConstClass(node_vtable)) [] + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) + guard_nonnull(p1) [] + guard_is_object(p1) [] + guard_class(p1, ConstClass(node_vtable)) [] jump(p0) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr]) def test_lenbound_array(self): loop = """ [p0] - i2 = getarrayitem_gc(p0, 10, descr=arraydescr) - call(i2, descr=nonwritedescr) + i2 = getarrayitem_gc_i(p0, 10, descr=arraydescr) + call_n(i2, descr=nonwritedescr) jump(p0) """ expected = """ [p0] - i2 = getarrayitem_gc(p0, 10, descr=arraydescr) - call(i2, descr=nonwritedescr) + i2 = getarrayitem_gc_i(p0, 10, descr=arraydescr) + call_n(i2, descr=nonwritedescr) + ifoo = arraylen_gc(p0, descr=arraydescr) jump(p0, i2) """ - self.optimize_bridge(loop, loop, expected, 'Loop0') + self.optimize_bridge(loop, loop, expected, 'Loop0', [self.myptr]) bridge = """ [p0] - i2 = getarrayitem_gc(p0, 15, descr=arraydescr) + i2 = getarrayitem_gc_i(p0, 15, descr=arraydescr) jump(p0) """ expected = """ [p0] - i2 = getarrayitem_gc(p0, 15, descr=arraydescr) - i3 = getarrayitem_gc(p0, 10, descr=arraydescr) + i2 = getarrayitem_gc_i(p0, 15, descr=arraydescr) + ifoo = arraylen_gc(p0, descr=arraydescr) + i3 = getarrayitem_gc_i(p0, 10, descr=arraydescr) jump(p0, i3) """ - self.optimize_bridge(loop, bridge, expected, 'Loop0') + self.optimize_bridge(loop, bridge, expected, 'Loop0', [self.myptr]) bridge = """ [p0] - i2 = getarrayitem_gc(p0, 5, descr=arraydescr) + i2 = getarrayitem_gc_i(p0, 5, descr=arraydescr) jump(p0) """ self.optimize_bridge(loop, bridge, 'RETRACE') @@ -1136,50 +1176,50 @@ def test_cached_lenbound_array(self): loop = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 10, descr=arraydescr) - call(i2, descr=nonwritedescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 10, descr=arraydescr) + call_n(i2, descr=nonwritedescr) jump(p0) """ expected = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 10, descr=arraydescr) - call(i2, descr=nonwritedescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 10, descr=arraydescr) + call_n(i2, descr=nonwritedescr) i3 = arraylen_gc(p1, descr=arraydescr) # Should be killed by backend - jump(p0, i2, p1) + jump(p0, p1, i2) """ self.optimize_bridge(loop, loop, expected) bridge = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 15, descr=arraydescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 15, descr=arraydescr) jump(p0) """ expected = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 15, descr=arraydescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 15, descr=arraydescr) i3 = arraylen_gc(p1, descr=arraydescr) # Should be killed by backend - i4 = getarrayitem_gc(p1, 10, descr=arraydescr) - jump(p0, i4, p1) + i4 = getarrayitem_gc_i(p1, 10, descr=arraydescr) + jump(p0, p1, i4) """ self.optimize_bridge(loop, bridge, expected) bridge = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 5, descr=arraydescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 5, descr=arraydescr) jump(p0) """ expected = """ [p0] - p1 = getfield_gc(p0, descr=nextdescr) - i2 = getarrayitem_gc(p1, 5, descr=arraydescr) + p1 = getfield_gc_r(p0, descr=nextdescr) + i2 = getarrayitem_gc_i(p1, 5, descr=arraydescr) i3 = arraylen_gc(p1, descr=arraydescr) # Should be killed by backend i4 = int_ge(i3, 11) guard_true(i4) [] - i5 = getarrayitem_gc(p1, 10, descr=arraydescr) - jump(p0, i5, p1) + i5 = getarrayitem_gc_i(p1, 10, descr=arraydescr) + jump(p0, p1, i5) """ self.optimize_bridge(loop, bridge, expected) bridge = """ @@ -1189,24 +1229,27 @@ expected = """ [p0] guard_nonnull(p0) [] - p1 = getfield_gc(p0, descr=nextdescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p1 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p1) [] + guard_gc_type(p1, ConstInt(arraydescr_tid)) [] i3 = arraylen_gc(p1, descr=arraydescr) # Should be killed by backend i4 = int_ge(i3, 11) guard_true(i4) [] - i5 = getarrayitem_gc(p1, 10, descr=arraydescr) - jump(p0, i5, p1) + i5 = getarrayitem_gc_i(p1, 10, descr=arraydescr) + jump(p0, p1, i5) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr]) def test_cached_setarrayitem_gc(self): loop = """ [p0, p1] - p2 = getfield_gc(p0, descr=nextdescr) - pp = getarrayitem_gc(p2, 0, descr=arraydescr) - call(pp, descr=nonwritedescr) - p3 = getfield_gc(p1, descr=nextdescr) - setarrayitem_gc(p2, 0, p3, descr=arraydescr) + p2 = getfield_gc_r(p0, descr=nextdescr) + pp = getarrayitem_gc_r(p2, 0, descr=gcarraydescr) + call_n(pp, descr=nonwritedescr) + p3 = getfield_gc_r(p1, descr=nextdescr) + setarrayitem_gc(p2, 0, p3, descr=gcarraydescr) jump(p0, p3) """ bridge = """ @@ -1216,21 +1259,25 @@ expected = """ [p0, p1] guard_nonnull(p0) [] - p2 = getfield_gc(p0, descr=nextdescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + p2 = getfield_gc_r(p0, descr=nextdescr) guard_nonnull(p2) [] - i5 = arraylen_gc(p2, descr=arraydescr) + guard_gc_type(p2, ConstInt(gcarraydescr_tid)) [] + i5 = arraylen_gc(p2, descr=gcarraydescr) i6 = int_ge(i5, 1) guard_true(i6) [] - p3 = getarrayitem_gc(p2, 0, descr=arraydescr) - jump(p0, p1, p3, p2) + p3 = getarrayitem_gc_r(p2, 0, descr=gcarraydescr) + jump(p0, p1, p2, p3) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr, + None]) def test_cache_constant_setfield(self): loop = """ [p5] - i10 = getfield_gc(p5, descr=valuedescr) - call(i10, descr=nonwritedescr) + i10 = getfield_gc_i(p5, descr=valuedescr) + call_n(i10, descr=nonwritedescr) setfield_gc(p5, 1, descr=valuedescr) jump(p5) """ @@ -1241,11 +1288,13 @@ expected = """ [p0] guard_nonnull(p0) [] - i10 = getfield_gc(p0, descr=valuedescr) + guard_is_object(p0) [] + guard_subclass(p0, ConstClass(node_vtable)) [] + i10 = getfield_gc_i(p0, descr=valuedescr) guard_value(i10, 1) [] jump(p0) """ - self.optimize_bridge(loop, bridge, expected, p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Loop', [self.myptr]) bridge = """ [p0] setfield_gc(p0, 7, descr=valuedescr) @@ -1256,14 +1305,14 @@ setfield_gc(p0, 7, descr=valuedescr) jump(p0) """ - self.optimize_bridge(loop, bridge, expected, 'Preamble', p0=self.myptr) + self.optimize_bridge(loop, bridge, expected, 'Preamble', [self.myptr]) def test_cached_equal_fields(self): loop = """ [p5, p6] - i10 = getfield_gc(p5, descr=valuedescr) - i11 = getfield_gc(p6, descr=nextdescr) - call(i10, i11, descr=nonwritedescr) + i10 = getfield_gc_i(p5, descr=valuedescr) + i11 = getfield_gc_i(p6, descr=chardescr) + call_n(i10, i11, descr=nonwritedescr) setfield_gc(p6, i10, descr=nextdescr) jump(p5, p6) """ @@ -1275,145 +1324,16 @@ [p5, p6] guard_nonnull(p5) [] guard_nonnull(p6) [] - i10 = getfield_gc(p5, descr=valuedescr) - i11 = getfield_gc(p6, descr=nextdescr) + guard_is_object(p5) [] + guard_subclass(p5, ConstClass(node_vtable)) [] + i10 = getfield_gc_i(p5, descr=valuedescr) + guard_is_object(p6) [] + guard_subclass(p6, ConstClass(node_vtable)) [] + i11 = getfield_gc_i(p6, descr=chardescr) jump(p5, p6, i10, i11) """ - self.optimize_bridge(loop, bridge, expected, p5=self.myptr, p6=self.myptr2) - - def test_licm_boxed_opaque_getitem(self): - loop = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - mark_opaque_ptr(p2) - guard_class(p2, ConstClass(node_vtable)) [] - i3 = getfield_gc(p2, descr=otherdescr) - i4 = call(i3, descr=nonwritedescr) - jump(p1) - """ - bridge = """ - [p1] - guard_nonnull(p1) [] - jump(p1) - """ - expected = """ - [p1] - guard_nonnull(p1) [] - p2 = getfield_gc(p1, descr=nextdescr) - jump(p1) - """ - self.optimize_bridge(loop, bridge, expected, 'Preamble') - - bridge = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable2)) [] - jump(p1) - """ - expected = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable2)) [] - jump(p1) - """ - self.optimize_bridge(loop, bridge, expected, 'Preamble') - - bridge = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable)) [] - jump(p1) - """ - expected = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - guard_class(p2, ConstClass(node_vtable)) [] - i3 = getfield_gc(p2, descr=otherdescr) - jump(p1, i3) - """ - self.optimize_bridge(loop, bridge, expected, 'Loop') - - def test_licm_unboxed_opaque_getitem(self): - loop = """ - [p2] - mark_opaque_ptr(p2) - guard_class(p2, ConstClass(node_vtable)) [] - i3 = getfield_gc(p2, descr=otherdescr) - i4 = call(i3, descr=nonwritedescr) - jump(p2) - """ - bridge = """ - [p1] - guard_nonnull(p1) [] - jump(p1) - """ - self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr) - self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr2) - - bridge = """ - [p2] - guard_class(p2, ConstClass(node_vtable2)) [] - jump(p2) - """ - self.optimize_bridge(loop, bridge, 'RETRACE') - - bridge = """ - [p2] - guard_class(p2, ConstClass(node_vtable)) [] - jump(p2) - """ - expected = """ - [p2] - guard_class(p2, ConstClass(node_vtable)) [] - i3 = getfield_gc(p2, descr=otherdescr) - jump(p2, i3) - """ - self.optimize_bridge(loop, bridge, expected, 'Loop') - - def test_licm_virtual_opaque_getitem(self): - loop = """ - [p1] - p2 = getfield_gc(p1, descr=nextdescr) - mark_opaque_ptr(p2) - guard_class(p2, ConstClass(node_vtable)) [] - i3 = getfield_gc(p2, descr=otherdescr) - i4 = call(i3, descr=nonwritedescr) - p3 = new_with_vtable(ConstClass(node_vtable)) - setfield_gc(p3, p2, descr=nextdescr) - jump(p3) - """ - bridge = """ - [p1] - p3 = new_with_vtable(ConstClass(node_vtable)) - setfield_gc(p3, p1, descr=nextdescr) - jump(p3) - """ - self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr) - self.optimize_bridge(loop, bridge, 'RETRACE', p1=self.myptr2) - - bridge = """ - [p1] - p3 = new_with_vtable(ConstClass(node_vtable)) - guard_class(p1, ConstClass(node_vtable2)) [] - setfield_gc(p3, p1, descr=nextdescr) - jump(p3) - """ - self.optimize_bridge(loop, bridge, 'RETRACE') - - bridge = """ - [p1] - p3 = new_with_vtable(ConstClass(node_vtable)) - guard_class(p1, ConstClass(node_vtable)) [] - setfield_gc(p3, p1, descr=nextdescr) - jump(p3) - """ - expected = """ - [p1] - guard_class(p1, ConstClass(node_vtable)) [] - i3 = getfield_gc(p1, descr=otherdescr) - jump(p1, i3) - """ - self.optimize_bridge(loop, bridge, expected) + self.optimize_bridge(loop, bridge, expected, 'Loop', + [self.myptr, self.myptr2]) class TestLLtypeGuards(BaseTestGenerateGuards, LLtypeMixin): @@ -1425,6 +1345,9 @@ class TestShortBoxes: + + def setup_class(self): + py.test.skip("rewrite") def test_short_box_duplication_direct(self): class Optimizer(FakeOptimizer): From noreply at buildbot.pypy.org Mon Sep 7 23:11:45 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 23:11:45 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix runner tests Message-ID: <20150907211145.D50EA1C034D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79512:e8c41ff360ee Date: 2015-09-07 23:11 +0200 http://bitbucket.org/pypy/pypy/changeset/e8c41ff360ee/ Log: fix runner tests diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -1804,8 +1804,11 @@ def alloc_instance(self, T): - vtable_for_T = lltype.malloc(self.MY_VTABLE, immortal=True) - vtable_for_T_addr = llmemory.cast_ptr_to_adr(vtable_for_T) + if hasattr(T, 'parent'): + vtable_for_T = lltype.malloc(self.MY_VTABLE, immortal=True) + vtable_for_T_addr = llmemory.cast_ptr_to_adr(vtable_for_T) + else: + vtable_for_T = None cpu = self.cpu class FakeGCCache(object): pass @@ -1827,11 +1830,12 @@ elif T == self.U: t.parent.parent.parent.typeptr = vtable_for_T t_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, t)) - T_box = ConstInt(heaptracker.adr2int(vtable_for_T_addr)) if not hasattr(T, 'parent'): vtable = None + T_box = None else: vtable = vtable_for_T + T_box = ConstInt(heaptracker.adr2int(vtable_for_T_addr)) descr = cpu.sizeof(T, vtable) return t_box, T_box, descr @@ -3463,7 +3467,8 @@ x = cpu.bh_new(descrsize) lltype.cast_opaque_ptr(lltype.Ptr(S), x) # type check # - _, T, descrsize2 = self.alloc_instance(rclass.OBJECT) + X = lltype.GcStruct('X', ('parent', rclass.OBJECT)) + _, T, descrsize2 = self.alloc_instance(X) x = cpu.bh_new_with_vtable(descrsize2) lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), x) # type check # well... From noreply at buildbot.pypy.org Mon Sep 7 23:17:49 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 23:17:49 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: whack at tests Message-ID: <20150907211749.ECB531C0EEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79513:eab1d6e2c45b Date: 2015-09-07 23:17 +0200 http://bitbucket.org/pypy/pypy/changeset/eab1d6e2c45b/ Log: whack at tests 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 @@ -434,7 +434,7 @@ self.descrs[key] = descr return descr - def sizeof(self, S, vtable): + def sizeof(self, S, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): key = ('size', S) try: descr = self.descrs[key] diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -324,7 +324,7 @@ def cast_int_to_ptr(self, x, TYPE): return rffi.cast(TYPE, x) - def sizeof(self, S, vtable): + def sizeof(self, S, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): return get_size_descr(self.gc_ll_descr, S, vtable) def fielddescrof(self, STRUCT, fieldname): 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 @@ -13,24 +13,24 @@ T = lltype.GcStruct('T') S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(T))) - descr_s = get_size_descr(c0, S, None) - descr_t = get_size_descr(c0, T, None) + descr_s = get_size_descr(c0, S) + descr_t = get_size_descr(c0, T) assert descr_s.size == symbolic.get_size(S, False) assert descr_t.size == symbolic.get_size(T, False) assert descr_s.is_immutable() == False assert descr_t.is_immutable() == False assert descr_t.gc_fielddescrs == [] assert len(descr_s.gc_fielddescrs) == 1 - assert descr_s == get_size_descr(c0, S, None) - assert descr_s != get_size_descr(c1, S, None) + assert descr_s == get_size_descr(c0, S) + assert descr_s != get_size_descr(c1, S) # - descr_s = get_size_descr(c1, S, None) + descr_s = get_size_descr(c1, S) assert isinstance(descr_s.size, Symbolic) assert descr_s.is_immutable() == False PARENT = lltype.Struct('P', ('x', lltype.Ptr(T))) STRUCT = lltype.GcStruct('S', ('parent', PARENT), ('y', lltype.Ptr(T))) - descr_struct = get_size_descr(c0, STRUCT, None) + descr_struct = get_size_descr(c0, STRUCT) assert len(descr_struct.gc_fielddescrs) == 2 def test_get_size_descr_immut(): @@ -49,7 +49,7 @@ for STRUCT in [S, T, U, V]: for translated in [False, True]: c0 = GcCache(translated) - descr_s = get_size_descr(c0, STRUCT, None) + descr_s = get_size_descr(c0, STRUCT) assert descr_s.is_immutable() == True def test_get_field_descr(): @@ -329,7 +329,7 @@ S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Ptr(T)), ('z', lltype.Ptr(T))) - descr1 = get_size_descr(c0, S, None) + descr1 = get_size_descr(c0, S) s = symbolic.get_size(S, False) assert repr_of_descr(descr1) == '' % s # diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -1808,7 +1808,7 @@ vtable_for_T = lltype.malloc(self.MY_VTABLE, immortal=True) vtable_for_T_addr = llmemory.cast_ptr_to_adr(vtable_for_T) else: - vtable_for_T = None + vtable_for_T = lltype.nullptr(rclass.OBJECT_VTABLE) cpu = self.cpu class FakeGCCache(object): pass @@ -1831,7 +1831,7 @@ t.parent.parent.parent.typeptr = vtable_for_T t_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, t)) if not hasattr(T, 'parent'): - vtable = None + vtable = lltype.nullptr(rclass.OBJECT_VTABLE) T_box = None else: vtable = vtable_for_T @@ -1934,7 +1934,7 @@ def test_new_plain_struct(self): cpu = self.cpu S = lltype.GcStruct('S', ('x', lltype.Char), ('y', lltype.Char)) - sizedescr = cpu.sizeof(S, None) + sizedescr = cpu.sizeof(S) r1 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr) r2 = self.execute_operation(rop.NEW, [], 'ref', descr=sizedescr) assert r1 != r2 @@ -3463,7 +3463,7 @@ # descrfld_ry) #assert rs.y == a # - descrsize = cpu.sizeof(S, None) + descrsize = cpu.sizeof(S) x = cpu.bh_new(descrsize) lltype.cast_opaque_ptr(lltype.Ptr(S), x) # type check # @@ -4801,8 +4801,8 @@ py.test.skip("llgraph can't do zero_ptr_field") T = lltype.GcStruct('T') S = lltype.GcStruct('S', ('x', lltype.Ptr(T))) - tdescr = self.cpu.sizeof(T, None) - sdescr = self.cpu.sizeof(S, None) + tdescr = self.cpu.sizeof(T) + sdescr = self.cpu.sizeof(S) fielddescr = self.cpu.fielddescrof(S, 'x') loop = parse(""" [] From noreply at buildbot.pypy.org Mon Sep 7 23:30:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 23:30:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix some tests Message-ID: <20150907213053.585FB1C0EEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79514:f7b49dec8b9e Date: 2015-09-07 23:31 +0200 http://bitbucket.org/pypy/pypy/changeset/f7b49dec8b9e/ Log: fix some tests diff --git a/rpython/jit/backend/x86/test/test_basic.py b/rpython/jit/backend/x86/test/test_basic.py --- a/rpython/jit/backend/x86/test/test_basic.py +++ b/rpython/jit/backend/x86/test/test_basic.py @@ -8,6 +8,9 @@ class Jit386Mixin(support.LLJitMixin): type_system = 'lltype' CPUClass = getcpuclass() + # we have to disable unroll + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + basic = False def check_jumps(self, maxcount): pass 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 @@ -23,8 +23,9 @@ self.fieldname = fieldname class FakeSizeDescr(AbstractDescr): - def __init__(self, STRUCT): + def __init__(self, STRUCT, vtable=None): self.STRUCT = STRUCT + self.vtable = vtable class FakeArrayDescr(AbstractDescr): def __init__(self, ARRAY): diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py --- a/rpython/jit/codewriter/test/test_flatten.py +++ b/rpython/jit/codewriter/test/test_flatten.py @@ -58,7 +58,7 @@ return FakeDescr() def fielddescrof(self, STRUCT, name): return FakeDescr() - def sizeof(self, STRUCT): + def sizeof(self, STRUCT, vtable=None): return FakeDescr() def arraydescrof(self, ARRAY): return FakeDescr() diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -46,7 +46,7 @@ return ('interiorfielddescr', ARRAY, name) def arraydescrof(self, ARRAY): return FakeDescr(('arraydescr', ARRAY)) - def sizeof(self, STRUCT): + def sizeof(self, STRUCT, vtable=None): return FakeDescr(('sizedescr', STRUCT)) class FakeDescr(tuple): 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 @@ -31,7 +31,7 @@ def __repr__(self): return '' % self.fieldname class sizeof(AbstractDescr): - def __init__(self, STRUCT): + def __init__(self, STRUCT, vtable=None): self.STRUCT = STRUCT def __repr__(self): return '' diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -10,6 +10,7 @@ from rpython.jit.codewriter.policy import JitPolicy from rpython.jit.codewriter import codewriter, longlong from rpython.rlib.rfloat import isnan +from rpython.rlib.jit import ENABLE_ALL_OPTS from rpython.translator.backendopt.all import backend_optimizations @@ -164,6 +165,8 @@ class JitMixin: basic = True + enable_opts = ENABLE_ALL_OPTS + # Basic terminology: the JIT produces "loops" and "bridges". # Bridges are always attached to failing guards. Every loop is @@ -180,7 +183,8 @@ the ones that end in FINISH. Either pass a dictionary (then the check must match exactly), or some keyword arguments (then the check is only about the instructions named).""" - get_stats().check_resops(expected=expected, **check) + if self.enable_opts == ENABLE_ALL_OPTS: + get_stats().check_resops(expected=expected, **check) def check_simple_loop(self, expected=None, **check): """Useful in the simplest case when we have only one loop @@ -188,51 +192,62 @@ Only the operations within the loop formed by that single jump will be counted; the bridges are all ignored. If several loops were compiled, complains.""" - get_stats().check_simple_loop(expected=expected, **check) + if self.enable_opts == ENABLE_ALL_OPTS: + get_stats().check_simple_loop(expected=expected, **check) def check_trace_count(self, count): # was check_loop_count """Check the number of loops and bridges compiled.""" - assert get_stats().compiled_count == count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().compiled_count == count def check_trace_count_at_most(self, count): """Check the number of loops and bridges compiled.""" - assert get_stats().compiled_count <= count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().compiled_count <= count def check_jitcell_token_count(self, count): # was check_tree_loop_count """This should check the number of independent trees of code. (xxx it is not 100% clear that the count is correct)""" - assert len(get_stats().jitcell_token_wrefs) == count + if self.enable_opts == ENABLE_ALL_OPTS: + assert len(get_stats().jitcell_token_wrefs) == count def check_target_token_count(self, count): """(xxx unknown)""" - tokens = get_stats().get_all_jitcell_tokens() - n = sum([len(t.target_tokens) for t in tokens]) - assert n == count + if self.enable_opts == ENABLE_ALL_OPTS: + tokens = get_stats().get_all_jitcell_tokens() + n = sum([len(t.target_tokens) for t in tokens]) + assert n == count def check_enter_count(self, count): """Check the number of times pyjitpl ran. (Every time, it should have produced either one loop or one bridge, or aborted; but it is not 100% clear that this is still correct in the presence of unrolling.)""" - assert get_stats().enter_count == count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().enter_count == count def check_enter_count_at_most(self, count): """Check the number of times pyjitpl ran.""" - assert get_stats().enter_count <= count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().enter_count <= count def check_aborted_count(self, count): """Check the number of times pyjitpl was aborted.""" - assert get_stats().aborted_count == count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().aborted_count == count def check_aborted_count_at_least(self, count): """Check the number of times pyjitpl was aborted.""" - assert get_stats().aborted_count >= count + if self.enable_opts == ENABLE_ALL_OPTS: + assert get_stats().aborted_count >= count def meta_interp(self, *args, **kwds): kwds['CPUClass'] = self.CPUClass kwds['type_system'] = self.type_system if "backendopt" not in kwds: kwds["backendopt"] = False + if "enable_opts" not in kwds and hasattr(self, 'enable_opts'): + kwds['enable_opts'] = self.enable_opts old = codewriter.CodeWriter.debug try: codewriter.CodeWriter.debug = True 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 @@ -2772,6 +2772,8 @@ raise InvalidLoop old_optimize_trace = optimizeopt.optimize_trace optimizeopt.optimize_trace = my_optimize_trace + if not self.basic: + py.test.skip("unrolling") try: res = self.meta_interp(f, [23, 4]) assert res == 23 @@ -2903,7 +2905,7 @@ res = self.meta_interp(f, [10, 7]) assert res == f(10, 7) self.check_jitcell_token_count(2) - if 0: + if self.basic: for cell in get_stats().get_all_jitcell_tokens(): assert len(cell.target_tokens) == 2 @@ -2913,8 +2915,9 @@ res = self.meta_interp(g, [10]) assert res == g(10) self.check_jitcell_token_count(2) - for cell in get_stats().get_all_jitcell_tokens(): - assert len(cell.target_tokens) <= 3 + if self.basic: + for cell in get_stats().get_all_jitcell_tokens(): + assert len(cell.target_tokens) <= 3 def g(n): return f(n, 2) + f(n, 3) + f(n, 4) + f(n, 5) + f(n, 6) + f(n, 7) @@ -2924,12 +2927,13 @@ # 2 loops and one function self.check_jitcell_token_count(3) cnt = 0 - for cell in get_stats().get_all_jitcell_tokens(): - if cell.target_tokens is None: - cnt += 1 - else: - assert len(cell.target_tokens) <= 4 - assert cnt == 1 + if self.basic: + for cell in get_stats().get_all_jitcell_tokens(): + if cell.target_tokens is None: + cnt += 1 + else: + assert len(cell.target_tokens) <= 4 + assert cnt == 1 def test_frame_finished_during_retrace(self): class Base(object): From noreply at buildbot.pypy.org Mon Sep 7 23:34:24 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 7 Sep 2015 23:34:24 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fixes Message-ID: <20150907213424.493F71C0EEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79515:caafa43c2558 Date: 2015-09-07 23:34 +0200 http://bitbucket.org/pypy/pypy/changeset/caafa43c2558/ Log: fixes diff --git a/rpython/jit/tool/test/test_jitoutput.py b/rpython/jit/tool/test/test_jitoutput.py --- a/rpython/jit/tool/test/test_jitoutput.py +++ b/rpython/jit/tool/test/test_jitoutput.py @@ -39,7 +39,7 @@ assert info.recorded_ops.total == 2 assert info.recorded_ops.calls == 0 assert info.guards == 2 - assert info.opt_ops == 13 + assert info.opt_ops == 11 assert info.opt_guards == 2 assert info.forcings == 0 diff --git a/rpython/jit/tool/test/test_oparser.py b/rpython/jit/tool/test/test_oparser.py --- a/rpython/jit/tool/test/test_oparser.py +++ b/rpython/jit/tool/test/test_oparser.py @@ -4,7 +4,7 @@ from rpython.jit.tool.oparser import parse, OpParser from rpython.jit.metainterp.resoperation import rop -from rpython.jit.metainterp.history import AbstractDescr, BoxInt, JitCellToken,\ +from rpython.jit.metainterp.history import AbstractDescr, JitCellToken,\ TargetToken class BaseTestOparser(object): From noreply at buildbot.pypy.org Tue Sep 8 10:07:53 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 10:07:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Adapt test_random.py (next is test_ll_random) Message-ID: <20150908080753.B0B2D1C11BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79516:7dd7112b93f3 Date: 2015-09-08 10:08 +0200 http://bitbucket.org/pypy/pypy/changeset/7dd7112b93f3/ Log: Adapt test_random.py (next is test_ll_random) diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -2,12 +2,13 @@ import pytest from rpython.rlib.rarithmetic import intmask, LONG_BIT from rpython.jit.metainterp.history import BasicFailDescr, TreeLoop, BasicFinalDescr -from rpython.jit.metainterp.history import BoxInt, ConstInt, JitCellToken, Box -from rpython.jit.metainterp.history import BoxPtr, ConstPtr, TargetToken -from rpython.jit.metainterp.history import BoxFloat, ConstFloat, Const -from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.metainterp.history import INT, ConstInt, JitCellToken +from rpython.jit.metainterp.history import REF, ConstPtr, TargetToken +from rpython.jit.metainterp.history import FLOAT, ConstFloat, Const, VOID from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.executor import execute_nonspec +from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef +from rpython.jit.metainterp.resoperation import InputArgFloat +from rpython.jit.metainterp.executor import execute_nonspec_const from rpython.jit.metainterp.resoperation import opname from rpython.jit.codewriter import longlong from rpython.rtyper.lltypesystem import lltype, rstr @@ -31,11 +32,11 @@ cpu._faildescr_keepalive = [] self.fakemetainterp = FakeMetaInterp() self.loop = loop - self.intvars = [box for box in vars if isinstance(box, BoxInt)] + self.intvars = [box for box in vars if box.type == INT] self.boolvars = [] # subset of self.intvars self.ptrvars = [] self.prebuilt_ptr_consts = [] - floatvars = [box for box in vars if isinstance(box, BoxFloat)] + floatvars = [box for box in vars if box.type == FLOAT] if cpu.supports_floats: self.floatvars = floatvars else: @@ -53,16 +54,15 @@ def do(self, opnum, argboxes, descr=None): self.fakemetainterp._got_exc = None - if opnum == rop.ZERO_PTR_FIELD: - v_result = None - else: - v_result = execute_nonspec(self.cpu, self.fakemetainterp, - opnum, argboxes, descr) - if isinstance(v_result, Const): - v_result = v_result.clonebox() - self.loop.operations.append(ResOperation(opnum, argboxes, v_result, - descr)) - return v_result + op = ResOperation(opnum, argboxes, descr) + if opnum != rop.ZERO_PTR_FIELD: + assert op.type != VOID, op + c_result = execute_nonspec_const(self.cpu, self.fakemetainterp, + opnum, argboxes, descr, + type=op.type) + op.copy_value_from(c_result) + self.loop.operations.append(op) + return op def get_bool_var(self, r): if self.boolvars and r.random() < 0.8: @@ -100,13 +100,13 @@ if v in names: args.append(names[v]) elif isinstance(v, ConstPtr): - assert not v.value # otherwise should be in the names + assert not v.getref_base() # otherwise should be in the names args.append('ConstPtr(lltype.nullptr(llmemory.GCREF.TO))') elif isinstance(v, ConstFloat): args.append('ConstFloat(longlong.getfloatstorage(%r))' % v.getfloat()) elif isinstance(v, ConstInt): - args.append('ConstInt(%s)' % v.value) + args.append('ConstInt(%s)' % v.getint()) else: raise NotImplementedError(v) if op.getdescr() is None: @@ -119,13 +119,13 @@ descrstr = ', TargetToken()' else: descrstr = ', descr=' + self.descr_counters.get(op.getdescr(), '...') - print >>s, ' ResOperation(rop.%s, [%s], %s%s),' % ( - opname[op.getopnum()], ', '.join(args), names[op.result], descrstr) + print >>s, ' %s = ResOperation(rop.%s, [%s]%s),' % ( + names[op], opname[op.getopnum()], ', '.join(args), descrstr) def print_loop(self, output, fail_descr=None, fail_args=None): def update_names(ops): for op in ops: - v = op.result + v = op if v not in names: writevar(v, 'tmp') if op.is_guard() or op.opnum == rop.FINISH: @@ -197,10 +197,10 @@ # def writevar(v, nameprefix, init=''): if nameprefix == 'const_ptr': - if not v.value: + if not v.getref_base(): return 'lltype.nullptr(llmemory.GCREF.TO)' - TYPE = v.value._obj.ORIGTYPE - cont = lltype.cast_opaque_ptr(TYPE, v.value) + TYPE = v.getref_base()._obj.ORIGTYPE + cont = lltype.cast_opaque_ptr(TYPE, v.getref_base()) if TYPE.TO._is_varsize(): if isinstance(TYPE.TO, lltype.GcStruct): lgt = len(cont.chars) @@ -249,8 +249,8 @@ if hasattr(self.loop, 'inputargs'): vals = [] for i, v in enumerate(self.loop.inputargs): - assert isinstance(v, Box) - if isinstance(v, BoxFloat): + assert not isinstance(v, Const) + if v.type == FLOAT: vals.append("longlong.getfloatstorage(%r)" % v.getfloat()) else: vals.append("%r" % v.getint()) @@ -261,12 +261,12 @@ else: fail_args = self.should_fail_by.getfailargs() for i, v in enumerate(fail_args): - if isinstance(v, (BoxFloat, ConstFloat)): + if v.type == FLOAT: print >>s, (' assert longlong.getrealfloat(' - 'cpu.get_float_value(frame, %d)) == %r' % (i, v.value)) + 'cpu.get_float_value(frame, %d)) == %r' % (i, v.getfloatstorage())) else: print >>s, (' assert cpu.get_int_value(frame, %d) == %d' - % (i, v.value)) + % (i, v.getint())) self.names = names s.flush() @@ -290,14 +290,14 @@ def put(self, builder, args, descr=None): v_result = builder.do(self.opnum, args, descr=descr) if v_result is not None: - if isinstance(v_result, BoxInt): + if v_result.type == INT: builder.intvars.append(v_result) boolres = self.boolres if boolres == 'sometimes': - boolres = v_result.value in [0, 1] + boolres = v_result.getint() in [0, 1] if boolres: builder.boolvars.append(v_result) - elif isinstance(v_result, BoxFloat): + elif v_result.type == FLOAT: builder.floatvars.append(v_result) assert self.boolres != True else: @@ -316,10 +316,8 @@ def produce_into(self, builder, r): if r.random() < 0.4: UnaryOperation.produce_into(self, builder, r) - elif r.random() < 0.75 or not builder.cpu.supports_floats: + else: self.put(builder, [ConstInt(r.random_integer())]) - else: - self.put(builder, [ConstFloat(r.random_float_storage())]) class SignExtOperation(AbstractOperation): def produce_into(self, builder, r): @@ -345,9 +343,11 @@ v_second = ConstInt((value & self.and_mask) | self.or_mask) else: v = r.choice(builder.intvars) - if (v.value & self.and_mask) != v.value: + v_value = v.getint() + if (v_value & self.and_mask) != v_value: v = builder.do(rop.INT_AND, [v, ConstInt(self.and_mask)]) - if (v.value | self.or_mask) != v.value: + v_value = v.getint() + if (v_value | self.or_mask) != v_value: v = builder.do(rop.INT_OR, [v, ConstInt(self.or_mask)]) v_second = v self.put(builder, [v_first, v_second]) @@ -359,14 +359,14 @@ super(AbstractOvfOperation, self).produce_into(builder, r) if builder.fakemetainterp._got_exc: # overflow detected assert isinstance(builder.fakemetainterp._got_exc, OverflowError) - op = ResOperation(rop.GUARD_OVERFLOW, [], None) + op = ResOperation(rop.GUARD_OVERFLOW, []) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including # the result, and then remove it from builder.intvars. fail_subset = builder.subset_of_intvars(r) builder.intvars[:] = original_intvars else: - op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) + op = ResOperation(rop.GUARD_NO_OVERFLOW, []) op.setdescr(builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -404,6 +404,13 @@ raise CannotProduceOperation self.put(builder, [r.choice(builder.floatvars)]) +class ConstUnaryFloatOperation(UnaryFloatOperation): + def produce_into(self, builder, r): + if r.random() < 0.4: + UnaryFloatOperation.produce_into(self, builder, r) + else: + self.put(builder, [ConstFloat(r.random_float_storage())]) + class CastIntToFloatOperation(AbstractFloatOperation): def produce_into(self, builder, r): self.put(builder, [r.choice(builder.intvars)]) @@ -429,9 +436,9 @@ class GuardOperation(AbstractOperation): def gen_guard(self, builder, r): v = builder.get_bool_var(r) - op = ResOperation(self.opnum, [v], None) - passing = ((self.opnum == rop.GUARD_TRUE and v.value) or - (self.opnum == rop.GUARD_FALSE and not v.value)) + op = ResOperation(self.opnum, [v]) + passing = ((self.opnum == rop.GUARD_TRUE and v.getint()) or + (self.opnum == rop.GUARD_FALSE and not v.getint())) return op, passing def produce_into(self, builder, r): @@ -448,9 +455,9 @@ if not builder.ptrvars: raise CannotProduceOperation box = r.choice(builder.ptrvars)[0] - op = ResOperation(self.opnum, [box], None) - passing = ((self.opnum == rop.GUARD_NONNULL and box.value) or - (self.opnum == rop.GUARD_ISNULL and not box.value)) + op = ResOperation(self.opnum, [box]) + passing = ((self.opnum == rop.GUARD_NONNULL and box.getref_base()) or + (self.opnum == rop.GUARD_ISNULL and not box.getref_base())) return op, passing class GuardValueOperation(GuardOperation): @@ -460,14 +467,14 @@ other = r.choice(builder.intvars) else: if r.random() < 0.75: - value = v.value + value = v.getint() elif r.random() < 0.5: - value = v.value ^ 1 + value = v.getint() ^ 1 else: value = r.random_integer() other = ConstInt(value) - op = ResOperation(self.opnum, [v, other], None) - return op, (v.value == other.value) + op = ResOperation(self.opnum, [v, other]) + return op, (v.getint() == other.getint()) # ____________________________________________________________ @@ -516,7 +523,8 @@ OPERATIONS.append(UnaryOperation(rop.INT_IS_TRUE, boolres=True)) OPERATIONS.append(UnaryOperation(rop.INT_IS_ZERO, boolres=True)) -OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS, boolres='sometimes')) +OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS_I, boolres='sometimes')) +OPERATIONS.append(ConstUnaryFloatOperation(rop.SAME_AS_F)) OPERATIONS.append(SignExtOperation(rop.INT_SIGNEXT)) for _op in [rop.INT_ADD_OVF, @@ -616,19 +624,19 @@ startvars = [] if cpu.supports_floats: # pick up a single threshold for the whole 'inputargs', so - # that some loops have no or mostly no BoxFloat while others + # that some loops have no or mostly no FLOATs while others # have a lot of them k = r.random() - # but make sure there is at least one BoxInt + # but make sure there is at least one INT at_least_once = r.randrange(0, pytest.config.option.n_vars) else: k = -1 at_least_once = 0 for i in range(pytest.config.option.n_vars): if r.random() < k and i != at_least_once: - startvars.append(BoxFloat(r.random_float_storage())) + startvars.append(InputArgFloat(r.random_float_storage())) else: - startvars.append(BoxInt(r.random_integer())) + startvars.append(InputArgInt(r.random_integer())) allow_delay = True else: allow_delay = False @@ -665,13 +673,13 @@ for i in range(position): op = loop.operations[i] if (not op.has_no_side_effect() - or not isinstance(op.result, (BoxInt, BoxFloat))): + or op.type not in (INT, FLOAT)): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars)+1) - self.startvars.insert(randompos, op.result) + self.startvars.insert(randompos, op) loop._targettoken = TargetToken() - loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars, None, + loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars, loop._targettoken)) def generate_ops(self, builder, r, loop, startvars, needs_a_label=False): @@ -704,7 +712,7 @@ endvars.append(v) r.shuffle(endvars) endvars = endvars[:1] - loop.operations.append(ResOperation(rop.FINISH, endvars, None, + loop.operations.append(ResOperation(rop.FINISH, endvars, descr=builder.getfaildescr(is_finish=True))) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by @@ -716,7 +724,12 @@ endvars = self.get_fail_args() self.expected = {} for v in endvars: - self.expected[v] = v.value + if v.type == INT: + self.expected[v] = v.getint() + elif v.type == FLOAT: + self.expected[v] = v.getfloatstorage() + else: + assert 0, v.type def runjitcelltoken(self): if self.startvars == self.loop.inputargs: @@ -729,7 +742,7 @@ box = box.constbox() args.append(box) self.cpu.compile_loop(self.loop.inputargs, - [ResOperation(rop.JUMP, args, None, + [ResOperation(rop.JUMP, args, descr=self.loop._targettoken)], self._initialjumploop_celltoken) return self._initialjumploop_celltoken @@ -744,7 +757,7 @@ def clear_state(self): for v, S, fields in self.prebuilt_ptr_consts: - container = v.value._obj.container + container = v.getref_base()._obj.container for name, value in fields.items(): if isinstance(name, str): setattr(container, name, value) @@ -762,14 +775,21 @@ # exc = cpu.grab_exc_value() # assert not exc - arguments = [box.value for box in self.loop.inputargs] + arguments = [] + for box in self.loop.inputargs: + if box.type == INT: + arguments.append(box.getint()) + elif box.type == FLOAT: + arguments.append(box.getfloatstorage()) + else: + assert 0, box.type deadframe = cpu.execute_token(self.runjitcelltoken(), *arguments) fail = cpu.get_latest_descr(deadframe) do_assert(fail is self.should_fail_by.getdescr(), "Got %r, expected %r" % (fail, self.should_fail_by.getdescr())) for i, v in enumerate(self.get_fail_args()): - if isinstance(v, (BoxFloat, ConstFloat)): + if v.type == FLOAT: value = cpu.get_float_value(deadframe, i) else: value = cpu.get_int_value(deadframe, i) @@ -792,10 +812,9 @@ def exc_handling(guard_op): # operations need to start with correct GUARD_EXCEPTION if guard_op._exc_box is None: - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) + op = ResOperation(rop.GUARD_NO_EXCEPTION, []) else: - op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], - BoxPtr()) + op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box]) op.setdescr(self.builder.getfaildescr()) op.setfailargs([]) return op @@ -845,7 +864,14 @@ raise AssertionError(box.type) subset.append(srcbox) # - args = [x.clonebox() for x in subset] + args = [] + for x in subset: + if x.type == INT: + args.append(InputArgInt(x.getint())) + elif x.type == FLOAT: + args.append(InputArgFloat(x.getfloatstorage())) + else: + assert 0, x.type rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) # done @@ -854,7 +880,7 @@ assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. - jump_op = ResOperation(rop.JUMP, subset, None, + jump_op = ResOperation(rop.JUMP, subset, descr=rl.loop._targettoken) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op From noreply at buildbot.pypy.org Tue Sep 8 10:26:40 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:26:40 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: skip unrolling if the cpu does not support guard_gc_type Message-ID: <20150908082640.773251C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79517:0494002efd6d Date: 2015-09-08 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/0494002efd6d/ Log: skip unrolling if the cpu does not support guard_gc_type diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -1049,6 +1049,7 @@ info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) except InvalidLoop: + #pdb.post_mortem(sys.exc_info()[2]) debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop 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 @@ -33,6 +33,8 @@ def build_opt_chain(metainterp_sd, enable_opts): optimizations = [] unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict + if not metainterp_sd.cpu.supports_guard_gc_type: + unroll = False for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: @@ -40,8 +42,7 @@ optimizations.append(o) if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts - or 'heap' not in enable_opts or 'unroll' not in enable_opts - or 'pure' not in enable_opts): + or 'heap' not in enable_opts or 'pure' not in enable_opts): optimizations.append(OptSimplify(unroll)) return optimizations, unroll 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 @@ -2772,9 +2772,9 @@ raise InvalidLoop old_optimize_trace = optimizeopt.optimize_trace optimizeopt.optimize_trace = my_optimize_trace - if not self.basic: - py.test.skip("unrolling") try: + if not self.basic: + py.test.skip("unrolling") res = self.meta_interp(f, [23, 4]) assert res == 23 assert False in seen From noreply at buildbot.pypy.org Tue Sep 8 10:26:42 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:26:42 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix result type Message-ID: <20150908082642.B6E471C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79518:628acab79c47 Date: 2015-09-08 10:26 +0200 http://bitbucket.org/pypy/pypy/changeset/628acab79c47/ Log: fix result type 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 @@ -474,6 +474,13 @@ def get_result_type(self): return self.result_type + def get_normalized_result_type(self): + if self.result_type == 'S': + return 'i' + if self.result_type == 'L': + return 'f' + return self.result_type + def get_result_size(self): return self.result_size 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 @@ -1565,7 +1565,7 @@ if resbox is not None: return resbox self.metainterp.vable_and_vrefs_before_residual_call() - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL: resbox = self.metainterp.direct_libffi_call(allboxes, descr, tp) @@ -1601,7 +1601,7 @@ return resbox else: effect = effectinfo.extraeffect - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if effect == effectinfo.EF_LOOPINVARIANT: if tp == 'i': return self.execute_varargs(rop.CALL_LOOPINVARIANT_I, diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -1021,7 +1021,7 @@ class OpHelpers(object): @staticmethod def call_for_descr(descr): - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if tp == 'i': return rop.CALL_I elif tp == 'r': @@ -1033,7 +1033,7 @@ @staticmethod def call_pure_for_descr(descr): - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if tp == 'i': return rop.CALL_PURE_I elif tp == 'r': @@ -1045,7 +1045,7 @@ @staticmethod def call_may_force_for_descr(descr): - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if tp == 'i': return rop.CALL_MAY_FORCE_I elif tp == 'r': @@ -1057,7 +1057,7 @@ @staticmethod def call_assembler_for_descr(descr): - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if tp == 'i': return rop.CALL_ASSEMBLER_I elif tp == 'r': @@ -1069,7 +1069,7 @@ @staticmethod def call_loopinvariant_for_descr(descr): - tp = descr.get_result_type() + tp = descr.get_normalized_result_type() if tp == 'i': return rop.CALL_LOOPINVARIANT_I elif tp == 'r': From noreply at buildbot.pypy.org Tue Sep 8 10:26:44 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:26:44 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: kill unused path Message-ID: <20150908082644.C79281C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79519:7a7f4bda97b0 Date: 2015-09-08 10:26 +0200 http://bitbucket.org/pypy/pypy/changeset/7a7f4bda97b0/ Log: kill unused path diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -48,7 +48,7 @@ # get the function address as an integer func = argboxes[0].getint() # do the call using the correct function from the cpu - if rettype == INT or rettype == 'S': # *S*ingle float + if rettype == INT: try: result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) except Exception, e: From noreply at buildbot.pypy.org Tue Sep 8 10:26:46 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:26:46 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150908082646.D23DA1C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79520:6cf467e2b9fb Date: 2015-09-08 10:26 +0200 http://bitbucket.org/pypy/pypy/changeset/6cf467e2b9fb/ Log: merge diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -2,12 +2,13 @@ import pytest from rpython.rlib.rarithmetic import intmask, LONG_BIT from rpython.jit.metainterp.history import BasicFailDescr, TreeLoop, BasicFinalDescr -from rpython.jit.metainterp.history import BoxInt, ConstInt, JitCellToken, Box -from rpython.jit.metainterp.history import BoxPtr, ConstPtr, TargetToken -from rpython.jit.metainterp.history import BoxFloat, ConstFloat, Const -from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.metainterp.history import INT, ConstInt, JitCellToken +from rpython.jit.metainterp.history import REF, ConstPtr, TargetToken +from rpython.jit.metainterp.history import FLOAT, ConstFloat, Const, VOID from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.executor import execute_nonspec +from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef +from rpython.jit.metainterp.resoperation import InputArgFloat +from rpython.jit.metainterp.executor import execute_nonspec_const from rpython.jit.metainterp.resoperation import opname from rpython.jit.codewriter import longlong from rpython.rtyper.lltypesystem import lltype, rstr @@ -31,11 +32,11 @@ cpu._faildescr_keepalive = [] self.fakemetainterp = FakeMetaInterp() self.loop = loop - self.intvars = [box for box in vars if isinstance(box, BoxInt)] + self.intvars = [box for box in vars if box.type == INT] self.boolvars = [] # subset of self.intvars self.ptrvars = [] self.prebuilt_ptr_consts = [] - floatvars = [box for box in vars if isinstance(box, BoxFloat)] + floatvars = [box for box in vars if box.type == FLOAT] if cpu.supports_floats: self.floatvars = floatvars else: @@ -53,16 +54,15 @@ def do(self, opnum, argboxes, descr=None): self.fakemetainterp._got_exc = None - if opnum == rop.ZERO_PTR_FIELD: - v_result = None - else: - v_result = execute_nonspec(self.cpu, self.fakemetainterp, - opnum, argboxes, descr) - if isinstance(v_result, Const): - v_result = v_result.clonebox() - self.loop.operations.append(ResOperation(opnum, argboxes, v_result, - descr)) - return v_result + op = ResOperation(opnum, argboxes, descr) + if opnum != rop.ZERO_PTR_FIELD: + assert op.type != VOID, op + c_result = execute_nonspec_const(self.cpu, self.fakemetainterp, + opnum, argboxes, descr, + type=op.type) + op.copy_value_from(c_result) + self.loop.operations.append(op) + return op def get_bool_var(self, r): if self.boolvars and r.random() < 0.8: @@ -100,13 +100,13 @@ if v in names: args.append(names[v]) elif isinstance(v, ConstPtr): - assert not v.value # otherwise should be in the names + assert not v.getref_base() # otherwise should be in the names args.append('ConstPtr(lltype.nullptr(llmemory.GCREF.TO))') elif isinstance(v, ConstFloat): args.append('ConstFloat(longlong.getfloatstorage(%r))' % v.getfloat()) elif isinstance(v, ConstInt): - args.append('ConstInt(%s)' % v.value) + args.append('ConstInt(%s)' % v.getint()) else: raise NotImplementedError(v) if op.getdescr() is None: @@ -119,13 +119,13 @@ descrstr = ', TargetToken()' else: descrstr = ', descr=' + self.descr_counters.get(op.getdescr(), '...') - print >>s, ' ResOperation(rop.%s, [%s], %s%s),' % ( - opname[op.getopnum()], ', '.join(args), names[op.result], descrstr) + print >>s, ' %s = ResOperation(rop.%s, [%s]%s),' % ( + names[op], opname[op.getopnum()], ', '.join(args), descrstr) def print_loop(self, output, fail_descr=None, fail_args=None): def update_names(ops): for op in ops: - v = op.result + v = op if v not in names: writevar(v, 'tmp') if op.is_guard() or op.opnum == rop.FINISH: @@ -197,10 +197,10 @@ # def writevar(v, nameprefix, init=''): if nameprefix == 'const_ptr': - if not v.value: + if not v.getref_base(): return 'lltype.nullptr(llmemory.GCREF.TO)' - TYPE = v.value._obj.ORIGTYPE - cont = lltype.cast_opaque_ptr(TYPE, v.value) + TYPE = v.getref_base()._obj.ORIGTYPE + cont = lltype.cast_opaque_ptr(TYPE, v.getref_base()) if TYPE.TO._is_varsize(): if isinstance(TYPE.TO, lltype.GcStruct): lgt = len(cont.chars) @@ -249,8 +249,8 @@ if hasattr(self.loop, 'inputargs'): vals = [] for i, v in enumerate(self.loop.inputargs): - assert isinstance(v, Box) - if isinstance(v, BoxFloat): + assert not isinstance(v, Const) + if v.type == FLOAT: vals.append("longlong.getfloatstorage(%r)" % v.getfloat()) else: vals.append("%r" % v.getint()) @@ -261,12 +261,12 @@ else: fail_args = self.should_fail_by.getfailargs() for i, v in enumerate(fail_args): - if isinstance(v, (BoxFloat, ConstFloat)): + if v.type == FLOAT: print >>s, (' assert longlong.getrealfloat(' - 'cpu.get_float_value(frame, %d)) == %r' % (i, v.value)) + 'cpu.get_float_value(frame, %d)) == %r' % (i, v.getfloatstorage())) else: print >>s, (' assert cpu.get_int_value(frame, %d) == %d' - % (i, v.value)) + % (i, v.getint())) self.names = names s.flush() @@ -290,14 +290,14 @@ def put(self, builder, args, descr=None): v_result = builder.do(self.opnum, args, descr=descr) if v_result is not None: - if isinstance(v_result, BoxInt): + if v_result.type == INT: builder.intvars.append(v_result) boolres = self.boolres if boolres == 'sometimes': - boolres = v_result.value in [0, 1] + boolres = v_result.getint() in [0, 1] if boolres: builder.boolvars.append(v_result) - elif isinstance(v_result, BoxFloat): + elif v_result.type == FLOAT: builder.floatvars.append(v_result) assert self.boolres != True else: @@ -316,10 +316,8 @@ def produce_into(self, builder, r): if r.random() < 0.4: UnaryOperation.produce_into(self, builder, r) - elif r.random() < 0.75 or not builder.cpu.supports_floats: + else: self.put(builder, [ConstInt(r.random_integer())]) - else: - self.put(builder, [ConstFloat(r.random_float_storage())]) class SignExtOperation(AbstractOperation): def produce_into(self, builder, r): @@ -345,9 +343,11 @@ v_second = ConstInt((value & self.and_mask) | self.or_mask) else: v = r.choice(builder.intvars) - if (v.value & self.and_mask) != v.value: + v_value = v.getint() + if (v_value & self.and_mask) != v_value: v = builder.do(rop.INT_AND, [v, ConstInt(self.and_mask)]) - if (v.value | self.or_mask) != v.value: + v_value = v.getint() + if (v_value | self.or_mask) != v_value: v = builder.do(rop.INT_OR, [v, ConstInt(self.or_mask)]) v_second = v self.put(builder, [v_first, v_second]) @@ -359,14 +359,14 @@ super(AbstractOvfOperation, self).produce_into(builder, r) if builder.fakemetainterp._got_exc: # overflow detected assert isinstance(builder.fakemetainterp._got_exc, OverflowError) - op = ResOperation(rop.GUARD_OVERFLOW, [], None) + op = ResOperation(rop.GUARD_OVERFLOW, []) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including # the result, and then remove it from builder.intvars. fail_subset = builder.subset_of_intvars(r) builder.intvars[:] = original_intvars else: - op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) + op = ResOperation(rop.GUARD_NO_OVERFLOW, []) op.setdescr(builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -404,6 +404,13 @@ raise CannotProduceOperation self.put(builder, [r.choice(builder.floatvars)]) +class ConstUnaryFloatOperation(UnaryFloatOperation): + def produce_into(self, builder, r): + if r.random() < 0.4: + UnaryFloatOperation.produce_into(self, builder, r) + else: + self.put(builder, [ConstFloat(r.random_float_storage())]) + class CastIntToFloatOperation(AbstractFloatOperation): def produce_into(self, builder, r): self.put(builder, [r.choice(builder.intvars)]) @@ -429,9 +436,9 @@ class GuardOperation(AbstractOperation): def gen_guard(self, builder, r): v = builder.get_bool_var(r) - op = ResOperation(self.opnum, [v], None) - passing = ((self.opnum == rop.GUARD_TRUE and v.value) or - (self.opnum == rop.GUARD_FALSE and not v.value)) + op = ResOperation(self.opnum, [v]) + passing = ((self.opnum == rop.GUARD_TRUE and v.getint()) or + (self.opnum == rop.GUARD_FALSE and not v.getint())) return op, passing def produce_into(self, builder, r): @@ -448,9 +455,9 @@ if not builder.ptrvars: raise CannotProduceOperation box = r.choice(builder.ptrvars)[0] - op = ResOperation(self.opnum, [box], None) - passing = ((self.opnum == rop.GUARD_NONNULL and box.value) or - (self.opnum == rop.GUARD_ISNULL and not box.value)) + op = ResOperation(self.opnum, [box]) + passing = ((self.opnum == rop.GUARD_NONNULL and box.getref_base()) or + (self.opnum == rop.GUARD_ISNULL and not box.getref_base())) return op, passing class GuardValueOperation(GuardOperation): @@ -460,14 +467,14 @@ other = r.choice(builder.intvars) else: if r.random() < 0.75: - value = v.value + value = v.getint() elif r.random() < 0.5: - value = v.value ^ 1 + value = v.getint() ^ 1 else: value = r.random_integer() other = ConstInt(value) - op = ResOperation(self.opnum, [v, other], None) - return op, (v.value == other.value) + op = ResOperation(self.opnum, [v, other]) + return op, (v.getint() == other.getint()) # ____________________________________________________________ @@ -516,7 +523,8 @@ OPERATIONS.append(UnaryOperation(rop.INT_IS_TRUE, boolres=True)) OPERATIONS.append(UnaryOperation(rop.INT_IS_ZERO, boolres=True)) -OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS, boolres='sometimes')) +OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS_I, boolres='sometimes')) +OPERATIONS.append(ConstUnaryFloatOperation(rop.SAME_AS_F)) OPERATIONS.append(SignExtOperation(rop.INT_SIGNEXT)) for _op in [rop.INT_ADD_OVF, @@ -616,19 +624,19 @@ startvars = [] if cpu.supports_floats: # pick up a single threshold for the whole 'inputargs', so - # that some loops have no or mostly no BoxFloat while others + # that some loops have no or mostly no FLOATs while others # have a lot of them k = r.random() - # but make sure there is at least one BoxInt + # but make sure there is at least one INT at_least_once = r.randrange(0, pytest.config.option.n_vars) else: k = -1 at_least_once = 0 for i in range(pytest.config.option.n_vars): if r.random() < k and i != at_least_once: - startvars.append(BoxFloat(r.random_float_storage())) + startvars.append(InputArgFloat(r.random_float_storage())) else: - startvars.append(BoxInt(r.random_integer())) + startvars.append(InputArgInt(r.random_integer())) allow_delay = True else: allow_delay = False @@ -665,13 +673,13 @@ for i in range(position): op = loop.operations[i] if (not op.has_no_side_effect() - or not isinstance(op.result, (BoxInt, BoxFloat))): + or op.type not in (INT, FLOAT)): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars)+1) - self.startvars.insert(randompos, op.result) + self.startvars.insert(randompos, op) loop._targettoken = TargetToken() - loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars, None, + loop.operations.insert(position, ResOperation(rop.LABEL, self.startvars, loop._targettoken)) def generate_ops(self, builder, r, loop, startvars, needs_a_label=False): @@ -704,7 +712,7 @@ endvars.append(v) r.shuffle(endvars) endvars = endvars[:1] - loop.operations.append(ResOperation(rop.FINISH, endvars, None, + loop.operations.append(ResOperation(rop.FINISH, endvars, descr=builder.getfaildescr(is_finish=True))) if builder.should_fail_by: self.should_fail_by = builder.should_fail_by @@ -716,7 +724,12 @@ endvars = self.get_fail_args() self.expected = {} for v in endvars: - self.expected[v] = v.value + if v.type == INT: + self.expected[v] = v.getint() + elif v.type == FLOAT: + self.expected[v] = v.getfloatstorage() + else: + assert 0, v.type def runjitcelltoken(self): if self.startvars == self.loop.inputargs: @@ -729,7 +742,7 @@ box = box.constbox() args.append(box) self.cpu.compile_loop(self.loop.inputargs, - [ResOperation(rop.JUMP, args, None, + [ResOperation(rop.JUMP, args, descr=self.loop._targettoken)], self._initialjumploop_celltoken) return self._initialjumploop_celltoken @@ -744,7 +757,7 @@ def clear_state(self): for v, S, fields in self.prebuilt_ptr_consts: - container = v.value._obj.container + container = v.getref_base()._obj.container for name, value in fields.items(): if isinstance(name, str): setattr(container, name, value) @@ -762,14 +775,21 @@ # exc = cpu.grab_exc_value() # assert not exc - arguments = [box.value for box in self.loop.inputargs] + arguments = [] + for box in self.loop.inputargs: + if box.type == INT: + arguments.append(box.getint()) + elif box.type == FLOAT: + arguments.append(box.getfloatstorage()) + else: + assert 0, box.type deadframe = cpu.execute_token(self.runjitcelltoken(), *arguments) fail = cpu.get_latest_descr(deadframe) do_assert(fail is self.should_fail_by.getdescr(), "Got %r, expected %r" % (fail, self.should_fail_by.getdescr())) for i, v in enumerate(self.get_fail_args()): - if isinstance(v, (BoxFloat, ConstFloat)): + if v.type == FLOAT: value = cpu.get_float_value(deadframe, i) else: value = cpu.get_int_value(deadframe, i) @@ -792,10 +812,9 @@ def exc_handling(guard_op): # operations need to start with correct GUARD_EXCEPTION if guard_op._exc_box is None: - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None) + op = ResOperation(rop.GUARD_NO_EXCEPTION, []) else: - op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box], - BoxPtr()) + op = ResOperation(rop.GUARD_EXCEPTION, [guard_op._exc_box]) op.setdescr(self.builder.getfaildescr()) op.setfailargs([]) return op @@ -845,7 +864,14 @@ raise AssertionError(box.type) subset.append(srcbox) # - args = [x.clonebox() for x in subset] + args = [] + for x in subset: + if x.type == INT: + args.append(InputArgInt(x.getint())) + elif x.type == FLOAT: + args.append(InputArgFloat(x.getfloatstorage())) + else: + assert 0, x.type rl = RandomLoop(self.builder.cpu, self.builder.fork, r, args) # done @@ -854,7 +880,7 @@ assert len(rl.loop.inputargs) == len(args) # The new bridge's execution will end normally at its FINISH. # Just replace the FINISH with the JUMP to the new loop. - jump_op = ResOperation(rop.JUMP, subset, None, + jump_op = ResOperation(rop.JUMP, subset, descr=rl.loop._targettoken) subloop.operations[-1] = jump_op self.guard_op = rl.guard_op From noreply at buildbot.pypy.org Tue Sep 8 10:33:05 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 10:33:05 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Avoid 4 copies of this big function Message-ID: <20150908083305.15BE91C03B3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79521:2c583e310786 Date: 2015-09-08 10:33 +0200 http://bitbucket.org/pypy/pypy/changeset/2c583e310786/ Log: Avoid 4 copies of this big function diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -15,67 +15,70 @@ # ____________________________________________________________ +def _do_call(cpu, metainterp, argboxes, descr, ettype): + assert metainterp is not None + # count the number of arguments of the different types + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + type = argboxes[i].type + if type == INT: count_i += 1 + elif type == REF: count_r += 1 + elif type == FLOAT: count_f += 1 + # allocate lists for each type that has at least one argument + if count_i: args_i = [0] * count_i + else: args_i = None + if count_r: args_r = [NULL] * count_r + else: args_r = None + if count_f: args_f = [longlong.ZEROF] * count_f + else: args_f = None + # fill in the lists + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + box = argboxes[i] + if box.type == INT: + args_i[count_i] = box.getint() + count_i += 1 + elif box.type == REF: + args_r[count_r] = box.getref_base() + count_r += 1 + elif box.type == FLOAT: + args_f[count_f] = box.getfloatstorage() + count_f += 1 + # get the function address as an integer + func = argboxes[0].getint() + # do the call using the correct function from the cpu + if rettype == INT: + try: + result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = 0 + return result + if rettype == REF: + try: + result = cpu.bh_call_r(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = NULL + return result + if rettype == FLOAT: + try: + result = cpu.bh_call_f(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = longlong.ZEROF + return result + if rettype == VOID: + try: + cpu.bh_call_v(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + return None + raise AssertionError("bad rettype") + def new_do_call(rettype): def do_call(cpu, metainterp, argboxes, descr): - assert metainterp is not None - # count the number of arguments of the different types - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - type = argboxes[i].type - if type == INT: count_i += 1 - elif type == REF: count_r += 1 - elif type == FLOAT: count_f += 1 - # allocate lists for each type that has at least one argument - if count_i: args_i = [0] * count_i - else: args_i = None - if count_r: args_r = [NULL] * count_r - else: args_r = None - if count_f: args_f = [longlong.ZEROF] * count_f - else: args_f = None - # fill in the lists - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - box = argboxes[i] - if box.type == INT: - args_i[count_i] = box.getint() - count_i += 1 - elif box.type == REF: - args_r[count_r] = box.getref_base() - count_r += 1 - elif box.type == FLOAT: - args_f[count_f] = box.getfloatstorage() - count_f += 1 - # get the function address as an integer - func = argboxes[0].getint() - # do the call using the correct function from the cpu - if rettype == INT: - try: - result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = 0 - return result - if rettype == REF: - try: - result = cpu.bh_call_r(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = NULL - return result - if rettype == FLOAT: - try: - result = cpu.bh_call_f(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = longlong.ZEROF - return result - if rettype == VOID: - try: - cpu.bh_call_v(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - return None - raise AssertionError("bad rettype") + return _do_call(cpu, metainterp, argboxes, descr, rettype) do_call.func_name = "do_call_" + rettype return do_call From noreply at buildbot.pypy.org Tue Sep 8 10:37:28 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:37:28 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Kill auto-generated file that does not fit in the current model Message-ID: <20150908083728.ADCBE1C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79522:1347bf9f7442 Date: 2015-09-08 10:36 +0200 http://bitbucket.org/pypy/pypy/changeset/1347bf9f7442/ Log: Kill auto-generated file that does not fit in the current model diff --git a/rpython/jit/backend/x86/test/test_regalloc2.py b/rpython/jit/backend/x86/test/test_regalloc2.py deleted file mode 100644 --- a/rpython/jit/backend/x86/test/test_regalloc2.py +++ /dev/null @@ -1,610 +0,0 @@ -from rpython.jit.metainterp.history import ResOperation, ConstInt,\ - BasicFailDescr, JitCellToken, BasicFinalDescr, TargetToken, ConstPtr,\ - ConstFloat -from rpython.jit.metainterp.resoperation import rop -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.backend.x86.arch import WORD -from rpython.jit.tool.oparser import parse -from rpython.rtyper.lltypesystem import lltype, rffi, llmemory, rstr -from rpython.rtyper import rclass -from rpython.rtyper.llinterp import LLException -from rpython.rtyper.annlowlevel import llhelper -from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.codewriter import longlong, heaptracker - -CPU = getcpuclass() - - -def test_bug_rshift(): - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - zero = InputArgInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_ADD, [v1, v1], v2), - ResOperation(rop.INT_INVERT, [v2], v3), - ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.SAME_AS, [ConstInt(0)], zero), - ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()) - ] - operations[-2].setfailargs([v4, v3]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, 9) - assert cpu.get_int_value(deadframe, 0) == (9 >> 3) - assert cpu.get_int_value(deadframe, 1) == (~18) - -def test_bug_int_is_true_1(): - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - zero = InputArgInt() - tmp5 = InputArgInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_MUL, [v1, v1], v2), - ResOperation(rop.INT_MUL, [v2, v1], v3), - ResOperation(rop.INT_IS_TRUE, [v2], tmp5), - ResOperation(rop.INT_IS_ZERO, [tmp5], v4), - ResOperation(rop.SAME_AS, [ConstInt(0)], zero), - ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()) - ] - operations[-2].setfailargs([v4, v3, tmp5]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, -10) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == -1000 - assert cpu.get_int_value(deadframe, 2) == 1 - -def test_bug_0(): - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - v5 = InputArgInt() - v6 = InputArgInt() - v7 = InputArgInt() - v8 = InputArgInt() - v9 = InputArgInt() - v10 = InputArgInt() - v11 = InputArgInt() - v12 = InputArgInt() - v13 = InputArgInt() - v14 = InputArgInt() - v15 = InputArgInt() - v16 = InputArgInt() - v17 = InputArgInt() - v18 = InputArgInt() - v19 = InputArgInt() - v20 = InputArgInt() - v21 = InputArgInt() - v22 = InputArgInt() - v23 = InputArgInt() - v24 = InputArgInt() - v25 = InputArgInt() - v26 = InputArgInt() - v27 = InputArgInt() - v28 = InputArgInt() - v29 = InputArgInt() - v30 = InputArgInt() - v31 = InputArgInt() - v32 = InputArgInt() - v33 = InputArgInt() - v34 = InputArgInt() - v35 = InputArgInt() - v36 = InputArgInt() - v37 = InputArgInt() - v38 = InputArgInt() - v39 = InputArgInt() - v40 = InputArgInt() - zero = InputArgInt() - tmp41 = InputArgInt() - tmp42 = InputArgInt() - tmp43 = InputArgInt() - tmp44 = InputArgInt() - tmp45 = InputArgInt() - tmp46 = InputArgInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_GT, [v3, ConstInt(-48)], v11), - ResOperation(rop.INT_XOR, [v8, v1], v12), - ResOperation(rop.INT_GT, [v6, ConstInt(-9)], v13), - ResOperation(rop.INT_LE, [v13, v2], v14), - ResOperation(rop.INT_LE, [v11, v5], v15), - ResOperation(rop.UINT_GE, [v13, v13], v16), - ResOperation(rop.INT_OR, [v9, ConstInt(-23)], v17), - ResOperation(rop.INT_LT, [v10, v13], v18), - ResOperation(rop.INT_OR, [v15, v5], v19), - ResOperation(rop.INT_XOR, [v17, ConstInt(54)], v20), - ResOperation(rop.INT_MUL, [v8, v10], v21), - ResOperation(rop.INT_OR, [v3, v9], v22), - ResOperation(rop.INT_AND, [v11, ConstInt(-4)], tmp41), - ResOperation(rop.INT_OR, [tmp41, ConstInt(1)], tmp42), - ResOperation(rop.INT_MOD, [v12, tmp42], v23), - ResOperation(rop.INT_IS_TRUE, [v6], v24), - ResOperation(rop.UINT_RSHIFT, [v15, ConstInt(6)], v25), - ResOperation(rop.INT_OR, [ConstInt(-4), v25], v26), - ResOperation(rop.INT_INVERT, [v8], v27), - ResOperation(rop.INT_SUB, [ConstInt(-113), v11], v28), - ResOperation(rop.INT_NEG, [v7], v29), - ResOperation(rop.INT_NEG, [v24], v30), - ResOperation(rop.INT_FLOORDIV, [v3, ConstInt(53)], v31), - ResOperation(rop.INT_MUL, [v28, v27], v32), - ResOperation(rop.INT_AND, [v18, ConstInt(-4)], tmp43), - ResOperation(rop.INT_OR, [tmp43, ConstInt(1)], tmp44), - ResOperation(rop.INT_MOD, [v26, tmp44], v33), - ResOperation(rop.INT_OR, [v27, v19], v34), - ResOperation(rop.UINT_LT, [v13, ConstInt(1)], v35), - ResOperation(rop.INT_AND, [v21, ConstInt(31)], tmp45), - ResOperation(rop.INT_RSHIFT, [v21, tmp45], v36), - ResOperation(rop.INT_AND, [v20, ConstInt(31)], tmp46), - ResOperation(rop.UINT_RSHIFT, [v4, tmp46], v37), - ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), - ResOperation(rop.INT_NEG, [v7], v39), - ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.SAME_AS, [ConstInt(0)], zero), - ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()) - ] - operations[-2].setfailargs([v40, v36, v37, v31, v16, v34, v35, v23, - v22, v29, v14, v39, v30, v38]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, -13, 10, 10, 8, -8, - -16, -18, 46, -12, 26) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 0 - assert cpu.get_int_value(deadframe, 2) == 0 - assert cpu.get_int_value(deadframe, 3) == 0 - assert cpu.get_int_value(deadframe, 4) == 1 - assert cpu.get_int_value(deadframe, 5) == -7 - assert cpu.get_int_value(deadframe, 6) == 1 - assert cpu.get_int_value(deadframe, 7) == 0 - assert cpu.get_int_value(deadframe, 8) == -2 - assert cpu.get_int_value(deadframe, 9) == 18 - assert cpu.get_int_value(deadframe, 10) == 1 - assert cpu.get_int_value(deadframe, 11) == 18 - assert cpu.get_int_value(deadframe, 12) == -1 - assert cpu.get_int_value(deadframe, 13) == 0 - -def test_bug_1(): - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - v5 = InputArgInt() - v6 = InputArgInt() - v7 = InputArgInt() - v8 = InputArgInt() - v9 = InputArgInt() - v10 = InputArgInt() - v11 = InputArgInt() - v12 = InputArgInt() - v13 = InputArgInt() - v14 = InputArgInt() - v15 = InputArgInt() - v16 = InputArgInt() - v17 = InputArgInt() - v18 = InputArgInt() - v19 = InputArgInt() - v20 = InputArgInt() - v21 = InputArgInt() - v22 = InputArgInt() - v23 = InputArgInt() - v24 = InputArgInt() - v25 = InputArgInt() - v26 = InputArgInt() - v27 = InputArgInt() - v28 = InputArgInt() - v29 = InputArgInt() - v30 = InputArgInt() - v31 = InputArgInt() - v32 = InputArgInt() - v33 = InputArgInt() - v34 = InputArgInt() - v35 = InputArgInt() - v36 = InputArgInt() - v37 = InputArgInt() - v38 = InputArgInt() - v39 = InputArgInt() - v40 = InputArgInt() - zero = InputArgInt() - tmp41 = InputArgInt() - tmp42 = InputArgInt() - tmp43 = InputArgInt() - tmp44 = InputArgInt() - tmp45 = InputArgInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_LT, [v6, ConstInt(0)], v11), - ResOperation(rop.INT_AND, [v3, ConstInt(31)], tmp41), - ResOperation(rop.INT_RSHIFT, [v3, tmp41], v12), - ResOperation(rop.INT_NEG, [v2], v13), - ResOperation(rop.INT_ADD, [v11, v7], v14), - ResOperation(rop.INT_OR, [v3, v2], v15), - ResOperation(rop.INT_OR, [v12, v12], v16), - ResOperation(rop.INT_NE, [v2, v5], v17), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp42), - ResOperation(rop.UINT_RSHIFT, [v14, tmp42], v18), - ResOperation(rop.INT_AND, [v14, ConstInt(31)], tmp43), - ResOperation(rop.INT_LSHIFT, [ConstInt(7), tmp43], v19), - ResOperation(rop.INT_NEG, [v19], v20), - ResOperation(rop.INT_MOD, [v3, ConstInt(1)], v21), - ResOperation(rop.UINT_GE, [v15, v1], v22), - ResOperation(rop.INT_AND, [v16, ConstInt(31)], tmp44), - ResOperation(rop.INT_LSHIFT, [v8, tmp44], v23), - ResOperation(rop.INT_IS_TRUE, [v17], v24), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp45), - ResOperation(rop.INT_LSHIFT, [v14, tmp45], v25), - ResOperation(rop.INT_LSHIFT, [v5, ConstInt(17)], v26), - ResOperation(rop.INT_EQ, [v9, v15], v27), - ResOperation(rop.INT_GE, [ConstInt(0), v6], v28), - ResOperation(rop.INT_NEG, [v15], v29), - ResOperation(rop.INT_NEG, [v22], v30), - ResOperation(rop.INT_ADD, [v7, v16], v31), - ResOperation(rop.UINT_LT, [v19, v19], v32), - ResOperation(rop.INT_ADD, [v2, ConstInt(1)], v33), - ResOperation(rop.INT_NEG, [v5], v34), - ResOperation(rop.INT_ADD, [v17, v24], v35), - ResOperation(rop.UINT_LT, [ConstInt(2), v16], v36), - ResOperation(rop.INT_NEG, [v9], v37), - ResOperation(rop.INT_GT, [v4, v11], v38), - ResOperation(rop.INT_LT, [v27, v22], v39), - ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.SAME_AS, [ConstInt(0)], zero), - ResOperation(rop.GUARD_TRUE, [zero], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()) - ] - operations[-2].setfailargs([v40, v10, v36, v26, v13, v30, v21, v33, - v18, v25, v31, v32, v28, v29, v35, v38, - v20, v39, v34, v23, v37]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, 17, -20, -6, 6, 1, - 13, 13, 9, 49, 8) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 8 - assert cpu.get_int_value(deadframe, 2) == 1 - assert cpu.get_int_value(deadframe, 3) == 131072 - assert cpu.get_int_value(deadframe, 4) == 20 - assert cpu.get_int_value(deadframe, 5) == -1 - assert cpu.get_int_value(deadframe, 6) == 0 - assert cpu.get_int_value(deadframe, 7) == -19 - assert cpu.get_int_value(deadframe, 8) == 6 - assert cpu.get_int_value(deadframe, 9) == 26 - assert cpu.get_int_value(deadframe, 10) == 12 - assert cpu.get_int_value(deadframe, 11) == 0 - assert cpu.get_int_value(deadframe, 12) == 0 - assert cpu.get_int_value(deadframe, 13) == 2 - assert cpu.get_int_value(deadframe, 14) == 2 - assert cpu.get_int_value(deadframe, 15) == 1 - assert cpu.get_int_value(deadframe, 16) == -57344 - assert cpu.get_int_value(deadframe, 17) == 1 - assert cpu.get_int_value(deadframe, 18) == -1 - if WORD == 4: - assert cpu.get_int_value(deadframe, 19) == -2147483648 - elif WORD == 8: - assert cpu.get_int_value(deadframe, 19) == 19327352832 - assert cpu.get_int_value(deadframe, 20) == -49 - -def getllhelper(cpu, f, ARGS, RES): - FPTR = lltype.Ptr(lltype.FuncType(ARGS, RES)) - fptr = llhelper(FPTR, f) - calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT, - EffectInfo.MOST_GENERAL) - return rffi.cast(lltype.Signed, fptr), calldescr - -def getexception(cpu, count): - xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) - xtp.subclassrange_min = 1 - xtp.subclassrange_max = 3 - X = lltype.GcStruct('X', ('parent', rclass.OBJECT), - hints={'vtable': xtp._obj}) - xptr = lltype.malloc(X) - vtableptr = X._hints['vtable']._as_ptr() - - def f(*args): - raise LLException(vtableptr, xptr) - - fptr, funcdescr = getllhelper(cpu, f, [lltype.Signed] * count, lltype.Void) - - return heaptracker.adr2int(llmemory.cast_ptr_to_adr(vtableptr)), fptr, funcdescr - -def getnoexception(cpu, count): - def f(*args): - return sum(args) - - return getllhelper(cpu, f, [lltype.Signed] * count, lltype.Signed) - -def getvtable(cpu, S=None): - cls1 = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) - cls1.subclassrange_min = 1 - cls1.subclassrange_max = 3 - if S is not None: - descr = cpu.sizeof(S, cls1) # xxx may be not needed any more - return llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(cls1), "symbolic") - -def test_bug_2(): - cpu = CPU(None, None) - cpu.setup_once() - - S4 = lltype.Struct('Sx', ("f0", lltype.Char), ("f1", lltype.Signed), ("f2", lltype.Signed), ("f3", lltype.Signed)) - S5 = lltype.GcArray(S4) - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - v5 = InputArgInt() - v6 = InputArgInt() - v7 = InputArgInt() - v8 = InputArgInt() - v9 = InputArgInt() - v10 = InputArgInt() - tmp11 = InputArgInt() - tmp12 = InputArgRef() - faildescr0 = BasicFailDescr() - tmp13 = InputArgRef() - faildescr1 = BasicFailDescr() - finishdescr2 = BasicFinalDescr() - const_ptr14 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.STR, 1))) - const_ptr15 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 489))) - const_ptr16 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 16))) - const_ptr17 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S5, 299))) - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - - xtp, func, funcdescr = getexception(cpu, 3) - xtp2, func2, func2descr = getexception(cpu, 2) - - operations = [ - ResOperation(rop.STRGETITEM, [const_ptr14, ConstInt(0)], tmp11), - ResOperation(rop.LABEL, [v1, v2, tmp11, v3, v4, v5, v6, v7, v8, v9, v10], None, TargetToken()), - ResOperation(rop.UNICODESETITEM, [const_ptr15, v4, ConstInt(22)], None), - ResOperation(rop.CALL, [ConstInt(func), v2, v1, v9], None, descr=funcdescr), - ResOperation(rop.GUARD_EXCEPTION, [ConstInt(xtp)], tmp12, descr=faildescr0), - ResOperation(rop.UNICODESETITEM, [const_ptr16, ConstInt(13), ConstInt(9)], None), - ResOperation(rop.SETINTERIORFIELD_GC, [const_ptr17, v3, v7], None, cpu.interiorfielddescrof(S5, 'f3')), - ResOperation(rop.CALL, [ConstInt(func2), v7, v10], None, descr=func2descr), - ResOperation(rop.GUARD_NO_EXCEPTION, [], tmp13, descr=faildescr1), - ResOperation(rop.FINISH, [], None, descr=finishdescr2), - ] - operations[4].setfailargs([v4, v8, v10, v2, v9, v7, v6, v1]) - operations[8].setfailargs([v3, v9, v2, v6, v4]) - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - loop_args = [1, -39, 46, 21, 16, 6, -4611686018427387905, 12, 14, 2] - frame = cpu.execute_token(looptoken, *loop_args) - assert cpu.get_int_value(frame, 0) == 46 - assert cpu.get_int_value(frame, 1) == 14 - assert cpu.get_int_value(frame, 2) == -39 - assert cpu.get_int_value(frame, 3) == 6 - assert cpu.get_int_value(frame, 4) == 21 - S4 = lltype.GcStruct('Sx', ("parent", rclass.OBJECT), ("f0", lltype.Signed)) - S5 = lltype.GcStruct('Sx', ("f0", lltype.Signed)) - S6 = lltype.GcArray(lltype.Signed) - S7 = lltype.GcStruct('Sx', ("parent", rclass.OBJECT), ("f0", lltype.Char)) - S8 = lltype.Struct('Sx', ("f0", lltype.Char), ("f1", lltype.Signed), ("f2", lltype.Signed), ("f3", lltype.Signed)) - S9 = lltype.GcArray(S8) - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - v5 = InputArgInt() - v6 = InputArgInt() - v7 = InputArgInt() - v8 = InputArgInt() - v9 = InputArgInt() - v10 = InputArgInt() - v11 = InputArgInt() - v12 = InputArgInt() - v13 = InputArgInt() - v14 = InputArgInt() - v15 = InputArgInt() - v16 = InputArgInt() - v17 = InputArgInt() - v18 = InputArgInt() - v19 = InputArgInt() - p20 = InputArgRef() - tmp21 = InputArgRef() - faildescr3 = BasicFailDescr() - tmp22 = InputArgRef() - faildescr4 = BasicFailDescr() - tmp23 = InputArgInt() - tmp24 = InputArgInt() - tmp25 = InputArgInt() - tmp26 = InputArgInt() - tmp27 = InputArgInt() - tmp28 = InputArgInt() - tmp29 = InputArgInt() - faildescr5 = BasicFailDescr() - tmp30 = InputArgRef() - faildescr6 = BasicFailDescr() - finishdescr7 = BasicFinalDescr() - const_ptr31 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S4))) - const_ptr32 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.STR, 46))) - const_ptr33 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S5))) - const_ptr34 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 26))) - const_ptr35 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 15))) - const_ptr36 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S7))) - const_ptr37 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.STR, 484))) - const_ptr38 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S9, 299))) - inputargs = [v1, v2, v3, v4, v5] - - func3, func3descr = getnoexception(cpu, 5) - xtp3, func4, func4descr = getexception(cpu, 10) - - operations = [ - ResOperation(rop.GUARD_EXCEPTION, [ConstInt(xtp2)], tmp21, descr=faildescr3), - ResOperation(rop.INT_IS_ZERO, [v4], v6), - ResOperation(rop.INT_NE, [v6, ConstInt(13)], v7), - ResOperation(rop.GETFIELD_GC, [const_ptr31], v8, cpu.fielddescrof(S4, 'f0')), - ResOperation(rop.STRSETITEM, [const_ptr32, v6, ConstInt(0)], None), - ResOperation(rop.NEWSTR, [ConstInt(5)], tmp22), - ResOperation(rop.STRSETITEM, [tmp22, ConstInt(0), ConstInt(42)], None), - ResOperation(rop.STRSETITEM, [tmp22, ConstInt(1), ConstInt(42)], None), - ResOperation(rop.STRSETITEM, [tmp22, ConstInt(2), ConstInt(20)], None), - ResOperation(rop.STRSETITEM, [tmp22, ConstInt(3), ConstInt(48)], None), - ResOperation(rop.STRSETITEM, [tmp22, ConstInt(4), ConstInt(6)], None), - ResOperation(rop.GETFIELD_GC, [const_ptr33], v9, cpu.fielddescrof(S5, 'f0')), - ResOperation(rop.UNICODESETITEM, [const_ptr34, ConstInt(24), ConstInt(65533)], None), - ResOperation(rop.GETFIELD_GC, [const_ptr31], v10, cpu.fielddescrof(S4, 'f0')), - ResOperation(rop.INT_NE, [v10, ConstInt(25)], v11), - ResOperation(rop.CALL, [ConstInt(func3), v5, v1, v8, v3, v2], v12, descr=func3descr), - ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=faildescr4), - ResOperation(rop.UNICODELEN, [const_ptr35], tmp23), - ResOperation(rop.NEW_ARRAY, [v2], p20, cpu.arraydescrof(S6)), - ResOperation(rop.GETFIELD_GC, [const_ptr36], v13, cpu.fielddescrof(S7, 'f0')), - ResOperation(rop.INT_OR, [v8, ConstInt(2)], tmp24), - ResOperation(rop.INT_FLOORDIV, [ConstInt(8), tmp24], v14), - ResOperation(rop.GETARRAYITEM_GC, [p20, ConstInt(3)], v15, cpu.arraydescrof(S6)), - ResOperation(rop.COPYSTRCONTENT, [tmp22, const_ptr37, ConstInt(1), ConstInt(163), ConstInt(0)], None), - ResOperation(rop.COPYUNICODECONTENT, [const_ptr35, const_ptr34, ConstInt(13), ConstInt(0), v6], None), - ResOperation(rop.STRGETITEM, [tmp22, v6], tmp25), - ResOperation(rop.STRGETITEM, [tmp22, ConstInt(0)], tmp26), - ResOperation(rop.GETINTERIORFIELD_GC, [const_ptr38, v13], v16, cpu.interiorfielddescrof(S9, 'f0')), - ResOperation(rop.INT_GE, [v4, v5], v17), - ResOperation(rop.INT_OR, [v13, ConstInt(2)], tmp27), - ResOperation(rop.INT_FLOORDIV, [ConstInt(12), tmp27], v18), - ResOperation(rop.INT_AND, [v1, ConstInt(-4)], tmp28), - ResOperation(rop.INT_OR, [tmp28, ConstInt(2)], tmp29), - ResOperation(rop.INT_FLOORDIV, [v15, tmp29], v19), - ResOperation(rop.GUARD_FALSE, [v17], None, descr=faildescr5), - ResOperation(rop.UNICODESETITEM, [const_ptr34, ConstInt(20), ConstInt(65522)], None), - ResOperation(rop.CALL, [ConstInt(func4), v3, v9, v10, v8, v11, v5, v13, v14, v15, v6], None, descr=func4descr), - ResOperation(rop.GUARD_NO_EXCEPTION, [], tmp30, descr=faildescr6), - ResOperation(rop.FINISH, [], None, descr=finishdescr7), - ] - operations[0].setfailargs([]) - operations[16].setfailargs([v5, v9]) - operations[34].setfailargs([]) - operations[37].setfailargs([v12, v19, v10, v7, v4, v8, v18, v15, v9]) - cpu.compile_bridge(faildescr1, inputargs, operations, looptoken) - frame = cpu.execute_token(looptoken, *loop_args) - #assert cpu.get_int_value(frame, 0) == -9223372036854775766 - assert cpu.get_int_value(frame, 1) == 0 - #assert cpu.get_int_value(frame, 2) == -9223372036854775808 - assert cpu.get_int_value(frame, 3) == 1 - assert cpu.get_int_value(frame, 4) == 6 - #assert cpu.get_int_value(frame, 5) == -9223372036854775808 - assert cpu.get_int_value(frame, 6) == 0 - assert cpu.get_int_value(frame, 7) == 0 - #assert cpu.get_int_value(frame, 8) == 26 - S4 = lltype.GcStruct('Sx', ("parent", rclass.OBJECT), ("f0", lltype.Signed), ("f1", lltype.Signed)) - S5 = lltype.GcStruct('Sx', ("parent", rclass.OBJECT), ("f0", lltype.Signed)) - S6 = lltype.GcStruct('Sx', ("f0", lltype.Signed), ("f1", rffi.UCHAR)) - v1 = InputArgInt() - v2 = InputArgInt() - v3 = InputArgInt() - v4 = InputArgInt() - v5 = InputArgInt() - v6 = InputArgInt() - v7 = InputArgInt() - v8 = InputArgInt() - v9 = InputArgInt() - v10 = InputArgInt() - v11 = InputArgInt() - v12 = InputArgInt() - v13 = InputArgInt() - v14 = InputArgInt() - v15 = InputArgInt() - v16 = InputArgInt() - v17 = InputArgInt() - v18 = InputArgInt() - tmp19 = InputArgRef() - faildescr8 = BasicFailDescr() - tmp20 = InputArgInt() - tmp21 = InputArgInt() - tmp22 = InputArgInt() - tmp23 = InputArgInt() - faildescr9 = BasicFailDescr() - tmp24 = InputArgInt() - tmp25 = InputArgInt() - tmp26 = InputArgInt() - tmp27 = InputArgRef() - tmp28 = InputArgRef() - faildescr10 = BasicFailDescr() - finishdescr11 = BasicFinalDescr() - const_ptr29 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S4))) - const_ptr30 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 26))) - const_ptr31 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.UNICODE, 1))) - const_ptr32 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S5))) - const_ptr33 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S6))) - const_ptr34 = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(rstr.STR, 26))) - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9] - operations = [ - ResOperation(rop.GUARD_EXCEPTION, [ConstInt(xtp3)], tmp19, descr=faildescr8), - ResOperation(rop.SETFIELD_GC, [const_ptr29, v7], None, cpu.fielddescrof(S4, 'f0')), - ResOperation(rop.UNICODEGETITEM, [const_ptr30, ConstInt(21)], tmp20), - ResOperation(rop.UNICODEGETITEM, [const_ptr30, ConstInt(10)], tmp21), - ResOperation(rop.UINT_RSHIFT, [v9, ConstInt(40)], v10), - ResOperation(rop.UNICODEGETITEM, [const_ptr30, ConstInt(25)], tmp22), - ResOperation(rop.INT_NE, [ConstInt(-8), v9], v11), - ResOperation(rop.INT_MUL_OVF, [v3, ConstInt(-4)], tmp23), - ResOperation(rop.GUARD_OVERFLOW, [], None, descr=faildescr9), - ResOperation(rop.UNICODESETITEM, [const_ptr31, ConstInt(0), ConstInt(50175)], None), - ResOperation(rop.UINT_GT, [v8, ConstInt(-6)], v12), - ResOperation(rop.GETFIELD_GC, [const_ptr32], v13, cpu.fielddescrof(S5, 'f0')), - ResOperation(rop.INT_AND, [ConstInt(8), v8], v14), - ResOperation(rop.INT_INVERT, [v1], v15), - ResOperation(rop.SETFIELD_GC, [const_ptr33, ConstInt(3)], None, cpu.fielddescrof(S6, 'f1')), - ResOperation(rop.INT_GE, [v14, v6], v16), - ResOperation(rop.INT_AND, [v5, ConstInt(-4)], tmp24), - ResOperation(rop.INT_OR, [tmp24, ConstInt(2)], tmp25), - ResOperation(rop.INT_FLOORDIV, [v9, tmp25], v17), - ResOperation(rop.STRLEN, [const_ptr34], tmp26), - ResOperation(rop.NEWSTR, [ConstInt(7)], tmp27), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(0), ConstInt(21)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(1), ConstInt(79)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(2), ConstInt(7)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(3), ConstInt(2)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(4), ConstInt(229)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(5), ConstInt(233)], None), - ResOperation(rop.STRSETITEM, [tmp27, ConstInt(6), ConstInt(208)], None), - ResOperation(rop.INT_LT, [ConstInt(-31), v10], v18), - ResOperation(rop.SAME_AS, [ConstPtr(lltype.nullptr(llmemory.GCREF.TO))], tmp28), - ResOperation(rop.GUARD_NONNULL_CLASS, [tmp28, ConstInt(xtp2)], None, descr=faildescr10), - ResOperation(rop.FINISH, [v4], None, descr=finishdescr11), - ] - operations[0].setfailargs([]) - operations[8].setfailargs([tmp23, v5, v3, v11, v6]) - operations[30].setfailargs([v6]) - cpu.compile_bridge(faildescr6, inputargs, operations, looptoken) - frame = cpu.execute_token(looptoken, *loop_args) - #assert cpu.get_int_value(frame, 0) == -9223372036854775808 - v1 = InputArgInt() - v2 = InputArgInt() - p3 = InputArgRef() - tmp4 = InputArgInt() - tmp5 = InputArgRef() - faildescr12 = BasicFailDescr() - finishdescr13 = BasicFinalDescr() - inputargs = [v1] - - _, func5, func5descr = getexception(cpu, 0) - vt = getvtable(cpu, S4) - - operations = [ - ResOperation(rop.INT_AND, [v1, ConstInt(63)], tmp4), - ResOperation(rop.INT_LSHIFT, [ConstInt(10), tmp4], v2), - ResOperation(rop.NEW_WITH_VTABLE, [ConstInt(vt)], p3), - ResOperation(rop.CALL, [ConstInt(func5)], None, descr=func5descr), - ResOperation(rop.GUARD_EXCEPTION, [ConstInt(xtp2)], tmp5, descr=faildescr12), - ResOperation(rop.FINISH, [], None, descr=finishdescr13), - ] - operations[4].setfailargs([v2]) - cpu.compile_bridge(faildescr10, inputargs, operations, looptoken) - frame = cpu.execute_token(looptoken, *loop_args) - #assert cpu.get_int_value(frame, 0) == 10 From noreply at buildbot.pypy.org Tue Sep 8 10:37:30 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:37:30 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix test Message-ID: <20150908083730.C67041C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79523:8d7bfab5c466 Date: 2015-09-08 10:37 +0200 http://bitbucket.org/pypy/pypy/changeset/8d7bfab5c466/ Log: fix test diff --git a/rpython/jit/backend/x86/test/test_recursive.py b/rpython/jit/backend/x86/test/test_recursive.py --- a/rpython/jit/backend/x86/test/test_recursive.py +++ b/rpython/jit/backend/x86/test/test_recursive.py @@ -25,6 +25,6 @@ ranges.append(tb) prev_traceback = tb return ranges - assert get_ranges(codemaps[2]) == [[4], [4, 2], [4], [4, 2], [4]] + assert get_ranges(codemaps[2]) == [[4], [4, 2], [4]] assert get_ranges(codemaps[1]) == [[2]] assert get_ranges(codemaps[0]) == [[2], []] From noreply at buildbot.pypy.org Tue Sep 8 10:37:32 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:37:32 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150908083732.DEA671C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79524:9b835ed7b81d Date: 2015-09-08 10:37 +0200 http://bitbucket.org/pypy/pypy/changeset/9b835ed7b81d/ Log: merge diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -15,67 +15,70 @@ # ____________________________________________________________ +def _do_call(cpu, metainterp, argboxes, descr, ettype): + assert metainterp is not None + # count the number of arguments of the different types + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + type = argboxes[i].type + if type == INT: count_i += 1 + elif type == REF: count_r += 1 + elif type == FLOAT: count_f += 1 + # allocate lists for each type that has at least one argument + if count_i: args_i = [0] * count_i + else: args_i = None + if count_r: args_r = [NULL] * count_r + else: args_r = None + if count_f: args_f = [longlong.ZEROF] * count_f + else: args_f = None + # fill in the lists + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + box = argboxes[i] + if box.type == INT: + args_i[count_i] = box.getint() + count_i += 1 + elif box.type == REF: + args_r[count_r] = box.getref_base() + count_r += 1 + elif box.type == FLOAT: + args_f[count_f] = box.getfloatstorage() + count_f += 1 + # get the function address as an integer + func = argboxes[0].getint() + # do the call using the correct function from the cpu + if rettype == INT: + try: + result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = 0 + return result + if rettype == REF: + try: + result = cpu.bh_call_r(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = NULL + return result + if rettype == FLOAT: + try: + result = cpu.bh_call_f(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + result = longlong.ZEROF + return result + if rettype == VOID: + try: + cpu.bh_call_v(func, args_i, args_r, args_f, descr) + except Exception, e: + metainterp.execute_raised(e) + return None + raise AssertionError("bad rettype") + def new_do_call(rettype): def do_call(cpu, metainterp, argboxes, descr): - assert metainterp is not None - # count the number of arguments of the different types - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - type = argboxes[i].type - if type == INT: count_i += 1 - elif type == REF: count_r += 1 - elif type == FLOAT: count_f += 1 - # allocate lists for each type that has at least one argument - if count_i: args_i = [0] * count_i - else: args_i = None - if count_r: args_r = [NULL] * count_r - else: args_r = None - if count_f: args_f = [longlong.ZEROF] * count_f - else: args_f = None - # fill in the lists - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - box = argboxes[i] - if box.type == INT: - args_i[count_i] = box.getint() - count_i += 1 - elif box.type == REF: - args_r[count_r] = box.getref_base() - count_r += 1 - elif box.type == FLOAT: - args_f[count_f] = box.getfloatstorage() - count_f += 1 - # get the function address as an integer - func = argboxes[0].getint() - # do the call using the correct function from the cpu - if rettype == INT: - try: - result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = 0 - return result - if rettype == REF: - try: - result = cpu.bh_call_r(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = NULL - return result - if rettype == FLOAT: - try: - result = cpu.bh_call_f(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - result = longlong.ZEROF - return result - if rettype == VOID: - try: - cpu.bh_call_v(func, args_i, args_r, args_f, descr) - except Exception, e: - metainterp.execute_raised(e) - return None - raise AssertionError("bad rettype") + return _do_call(cpu, metainterp, argboxes, descr, rettype) do_call.func_name = "do_call_" + rettype return do_call From noreply at buildbot.pypy.org Tue Sep 8 10:39:22 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:39:22 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: uncomment the part that checks cpumodel, but leave the note Message-ID: <20150908083922.697A71C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79525:d5442e2f791a Date: 2015-09-08 10:39 +0200 http://bitbucket.org/pypy/pypy/changeset/d5442e2f791a/ Log: uncomment the part that checks cpumodel, but leave the note diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -116,17 +116,17 @@ # proper fix would be to use some llop that is only rendered by the # JIT # - #try: - # from rpython.jit.backend import detect_cpu - # model = detect_cpu.autodetect() - # self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) - #except Exception: - # if self.space.config.translation.jit: - # raise - # else: - # pass # ok fine to ignore in this case - # - #if self.space.config.translation.jit: - ## features = detect_cpu.getcpufeatures(model) - # self.extra_interpdef('jit_backend_features', - # 'space.wrap(%r)' % features) + try: + from rpython.jit.backend import detect_cpu + model = detect_cpu.autodetect() + self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + except Exception: + if self.space.config.translation.jit: + raise + else: + pass # ok fine to ignore in this case + + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) From noreply at buildbot.pypy.org Tue Sep 8 10:49:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 10:49:00 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix jitlogparser tests Message-ID: <20150908084900.89CDD1C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79526:4032080f53ea Date: 2015-09-08 10:48 +0200 http://bitbucket.org/pypy/pypy/changeset/4032080f53ea/ Log: fix jitlogparser tests diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -116,6 +116,8 @@ # proper fix would be to use some llop that is only rendered by the # JIT # + if self.space.config.translation.fork_before == 'pyjitpl': + return try: from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect() diff --git a/rpython/tool/jitlogparser/test/logtest.log b/rpython/tool/jitlogparser/test/logtest.log --- a/rpython/tool/jitlogparser/test/logtest.log +++ b/rpython/tool/jitlogparser/test/logtest.log @@ -23,7 +23,7 @@ +179: i8 = int_add(i4, 1) debug_merge_point(0, ' #28 STORE_FAST') debug_merge_point(0, ' #31 JUMP_ABSOLUTE') -+183: i10 = getfield_raw(40564608, descr=) ++183: i10 = getfield_raw_i(40564608, descr=) +191: i12 = int_sub(i10, 1) +195: setfield_raw(40564608, i12, descr=) +203: i14 = int_lt(i12, 0) diff --git a/rpython/tool/jitlogparser/test/logtest2.log b/rpython/tool/jitlogparser/test/logtest2.log --- a/rpython/tool/jitlogparser/test/logtest2.log +++ b/rpython/tool/jitlogparser/test/logtest2.log @@ -118,19 +118,19 @@ [1cffd9b20d9f] {jit-log-opt-loop # Loop 0 ( #9 LOAD_FAST) : loop with 59 ops [p0, p1] -+110: p2 = getfield_gc(p0, descr=) -+124: p3 = getfield_gc(p0, descr=) -+128: p4 = getfield_gc(p0, descr=) -+132: i5 = getfield_gc(p0, descr=) -+140: p6 = getfield_gc(p0, descr=) -+144: i7 = getfield_gc(p0, descr=) -+148: i8 = getfield_gc(p0, descr=) -+152: p9 = getfield_gc(p0, descr=) -+156: p11 = getarrayitem_gc(p9, 0, descr=) -+160: p13 = getarrayitem_gc(p9, 1, descr=) -+164: p15 = getarrayitem_gc(p9, 2, descr=) -+168: p17 = getarrayitem_gc(p9, 3, descr=) -+172: p18 = getfield_gc(p0, descr=) ++110: p2 = getfield_gc_r(p0, descr=) ++124: p3 = getfield_gc_r(p0, descr=) ++128: p4 = getfield_gc_r(p0, descr=) ++132: i5 = getfield_gc_i(p0, descr=) ++140: p6 = getfield_gc_r(p0, descr=) ++144: i7 = getfield_gc_i(p0, descr=) ++148: i8 = getfield_gc_i(p0, descr=) ++152: p9 = getfield_gc_r(p0, descr=) ++156: p11 = getarrayitem_gc_r(p9, 0, descr=) ++160: p13 = getarrayitem_gc_r(p9, 1, descr=) ++164: p15 = getarrayitem_gc_r(p9, 2, descr=) ++168: p17 = getarrayitem_gc_r(p9, 3, descr=) ++172: p18 = getfield_gc_r(p0, descr=) +172: label(p0, p1, p2, p3, p4, i5, p6, i7, i8, p11, p13, p15, p17, descr=TargetToken(140003404595232)) debug_merge_point(0, 0, ' #9 LOAD_FAST') +251: guard_value(i7, 2, descr=) [i7, p1, p0, p2, p3, p4, i5, p6, i8, p11, p13, p15, p17] @@ -139,7 +139,7 @@ debug_merge_point(0, 0, ' #12 LOAD_CONST') +289: guard_value(p4, ConstPtr(ptr22), descr=) [p1, p0, p4, p2, p3, p6, p11, p13, p17] debug_merge_point(0, 0, ' #15 COMPARE_OP') -+308: i23 = getfield_gc_pure(p11, descr=) ++308: i23 = getfield_gc_pure_i(p11, descr=) +312: i25 = int_lt(i23, 10) guard_true(i25, descr=) [p1, p0, p11, p2, p3, p6, p13] debug_merge_point(0, 0, ' #18 POP_JUMP_IF_FALSE') @@ -152,7 +152,7 @@ debug_merge_point(0, 0, ' #34 STORE_FAST') debug_merge_point(0, 0, ' #37 JUMP_ABSOLUTE') +327: guard_not_invalidated(descr=) [p1, p0, p2, p3, p6, i27] -+327: i29 = getfield_raw(51804288, descr=) ++327: i29 = getfield_raw_i(51804288, descr=) +335: i31 = int_lt(i29, 0) guard_false(i31, descr=) [p1, p0, p2, p3, p6, i27] debug_merge_point(0, 0, ' #9 LOAD_FAST') @@ -172,7 +172,7 @@ debug_merge_point(0, 0, ' #34 STORE_FAST') debug_merge_point(0, 0, ' #37 JUMP_ABSOLUTE') +390: guard_not_invalidated(descr=) [p1, p0, p2, p3, p6, i33, None] -+390: i35 = getfield_raw(51804288, descr=) ++390: i35 = getfield_raw_i(51804288, descr=) +398: i36 = int_lt(i35, 0) guard_false(i36, descr=) [p1, p0, p2, p3, p6, i33, None] debug_merge_point(0, 0, ' #9 LOAD_FAST') @@ -262,32 +262,32 @@ [1cffd9ed0c35] {jit-log-opt-loop # Loop 1 ( #13 FOR_ITER) : loop with 82 ops [p0, p1] -+110: p2 = getfield_gc(p0, descr=) -+124: p3 = getfield_gc(p0, descr=) -+128: p4 = getfield_gc(p0, descr=) -+132: i5 = getfield_gc(p0, descr=) -+140: p6 = getfield_gc(p0, descr=) -+144: i7 = getfield_gc(p0, descr=) -+148: i8 = getfield_gc(p0, descr=) -+152: p9 = getfield_gc(p0, descr=) -+156: p11 = getarrayitem_gc(p9, 0, descr=) -+160: p13 = getarrayitem_gc(p9, 1, descr=) -+164: p15 = getarrayitem_gc(p9, 2, descr=) -+168: p17 = getarrayitem_gc(p9, 3, descr=) -+172: p18 = getfield_gc(p0, descr=) ++110: p2 = getfield_gc_r(p0, descr=) ++124: p3 = getfield_gc_r(p0, descr=) ++128: p4 = getfield_gc_r(p0, descr=) ++132: i5 = getfield_gc_i(p0, descr=) ++140: p6 = getfield_gc_r(p0, descr=) ++144: i7 = getfield_gc_i(p0, descr=) ++148: i8 = getfield_gc_i(p0, descr=) ++152: p9 = getfield_gc_r(p0, descr=) ++156: p11 = getarrayitem_gc_r(p9, 0, descr=) ++160: p13 = getarrayitem_gc_r(p9, 1, descr=) ++164: p15 = getarrayitem_gc_r(p9, 2, descr=) ++168: p17 = getarrayitem_gc_r(p9, 3, descr=) ++172: p18 = getfield_gc_r(p0, descr=) +172: label(p0, p1, p2, p3, p4, i5, p6, i7, i8, p11, p13, p15, p17, descr=TargetToken(140003443320224)) debug_merge_point(0, 0, ' #13 FOR_ITER') +244: guard_value(i7, 3, descr=) [i7, p1, p0, p2, p3, p4, i5, p6, i8, p11, p13, p15, p17] +254: guard_class(p15, 26177128, descr=) [p1, p0, p15, p2, p3, p4, i5, p6, p11, p13, p17] -+266: p21 = getfield_gc(p15, descr=) ++266: p21 = getfield_gc_r(p15, descr=) +270: guard_nonnull(p21, descr=) [p1, p0, p15, p21, p2, p3, p4, i5, p6, p11, p13, p17] -+279: i22 = getfield_gc(p15, descr=) -+283: p23 = getfield_gc(p21, descr=) ++279: i22 = getfield_gc_i(p15, descr=) ++283: p23 = getfield_gc_r(p21, descr=) +287: guard_class(p23, 26517736, descr=) [p1, p0, p15, i22, p23, p21, p2, p3, p4, i5, p6, p11, p13, p17] -+299: p25 = getfield_gc(p21, descr=) -+303: i26 = getfield_gc_pure(p25, descr=) -+307: i27 = getfield_gc_pure(p25, descr=) -+311: i28 = getfield_gc_pure(p25, descr=) ++299: p25 = getfield_gc_r(p21, descr=) ++303: i26 = getfield_gc_pure_i(p25, descr=) ++307: i27 = getfield_gc_pure_i(p25, descr=) ++311: i28 = getfield_gc_pure_i(p25, descr=) +315: i30 = int_lt(i22, 0) guard_false(i30, descr=) [p1, p0, p15, i22, i28, i27, i26, p2, p3, p4, i5, p6, p11, p13, p17] +325: i31 = int_ge(i22, i28) @@ -300,20 +300,20 @@ debug_merge_point(0, 0, ' #16 STORE_FAST') debug_merge_point(0, 0, ' #19 LOAD_FAST') debug_merge_point(0, 0, ' #22 LIST_APPEND') -+365: p37 = getfield_gc(p13, descr=) ++365: p37 = getfield_gc_r(p13, descr=) +369: guard_class(p37, 26402184, descr=) [p1, p0, p37, p13, p2, p3, p4, p6, p15, i33] -+382: p39 = getfield_gc(p13, descr=) -+386: i40 = getfield_gc(p39, descr=) ++382: p39 = getfield_gc_r(p13, descr=) ++386: i40 = getfield_gc_i(p39, descr=) +390: i42 = int_add(i40, 1) -+394: p43 = getfield_gc(p39, descr=) ++394: p43 = getfield_gc_r(p39, descr=) +394: i44 = arraylen_gc(p43, descr=) -+394: call(ConstClass(_ll_list_resize_ge_trampoline__v672___simple_call__function__), p39, i42, descr=) ++394: call_n(ConstClass(_ll_list_resize_ge_trampoline__v672___simple_call__function__), p39, i42, descr=) +506: guard_no_exception(descr=) [p1, p0, i40, i33, p39, p2, p3, p4, p6, p13, p15, None] -+521: p47 = getfield_gc(p39, descr=) ++521: p47 = getfield_gc_r(p39, descr=) +532: setarrayitem_gc(p47, i40, i33, descr=) debug_merge_point(0, 0, ' #25 JUMP_ABSOLUTE') +551: guard_not_invalidated(descr=) [p1, p0, p2, p3, p4, p6, p13, p15, i33] -+551: i49 = getfield_raw(51804288, descr=) ++551: i49 = getfield_raw_i(51804288, descr=) +559: i51 = int_lt(i49, 0) guard_false(i51, descr=) [p1, p0, p2, p3, p4, p6, p13, p15, i33] +569: guard_value(p4, ConstPtr(ptr52), descr=) [p1, p0, p4, p2, p3, p6, p13, p15, i33] @@ -328,18 +328,18 @@ debug_merge_point(0, 0, ' #16 STORE_FAST') debug_merge_point(0, 0, ' #19 LOAD_FAST') debug_merge_point(0, 0, ' #22 LIST_APPEND') -+659: i57 = getfield_gc(p39, descr=) ++659: i57 = getfield_gc_i(p39, descr=) +663: i58 = int_add(i57, 1) -+667: p59 = getfield_gc(p39, descr=) ++667: p59 = getfield_gc_r(p39, descr=) +667: i60 = arraylen_gc(p59, descr=) -+667: call(ConstClass(_ll_list_resize_ge_trampoline__v672___simple_call__function__), p39, i58, descr=) ++667: call_n(ConstClass(_ll_list_resize_ge_trampoline__v672___simple_call__function__), p39, i58, descr=) +744: setfield_gc(p15, i56, descr=) +755: guard_no_exception(descr=) [p1, p0, i57, i55, p39, p2, p3, p6, p13, p15, None] -+770: p61 = getfield_gc(p39, descr=) ++770: p61 = getfield_gc_r(p39, descr=) +781: setarrayitem_gc(p61, i57, i55, descr=) debug_merge_point(0, 0, ' #25 JUMP_ABSOLUTE') +793: guard_not_invalidated(descr=) [p1, p0, p2, p3, p6, p13, p15, i55, None] -+793: i62 = getfield_raw(51804288, descr=) ++793: i62 = getfield_raw_i(51804288, descr=) +801: i63 = int_lt(i62, 0) guard_false(i63, descr=) [p1, p0, p2, p3, p6, p13, p15, i55, None] debug_merge_point(0, 0, ' #13 FOR_ITER') diff --git a/rpython/tool/jitlogparser/test/test_parser.py b/rpython/tool/jitlogparser/test/test_parser.py --- a/rpython/tool/jitlogparser/test/test_parser.py +++ b/rpython/tool/jitlogparser/test/test_parser.py @@ -16,7 +16,7 @@ [i7] i9 = int_lt(i7, 1003) guard_true(i9, descr=) [] - i13 = getfield_raw(151937600, descr=) + i13 = getfield_raw_i(151937600, descr=) ''').operations assert len(ops) == 3 assert ops[0].name == 'int_lt' @@ -26,7 +26,7 @@ assert ops[0].repr() == 'i9 = int_lt(i7, 1003)' assert ops[2].descr is not None assert len(ops[2].args) == 1 - assert ops[-1].repr() == 'i13 = getfield_raw(151937600, descr=)' + assert ops[-1].repr() == 'i13 = getfield_raw_i(151937600, descr=)' def test_parse_non_code(): ops = parse(''' @@ -60,7 +60,7 @@ ops = parse(""" [] debug_merge_point(0, 0, ' #28 CALL_FUNCTION') - i18 = getfield_gc(p0, descr=) + i18 = getfield_gc_i(p0, descr=) debug_merge_point(1, 1, ' #0 LOAD_FAST') debug_merge_point(1, 1, ' #3 LOAD_CONST') debug_merge_point(1, 1, ' #7 RETURN_VALUE') @@ -146,8 +146,8 @@ def test_reassign_loops(): main = parse(''' - [v0] - guard_false(v0, descr=) [] + [i0] + guard_false(i0, descr=) [] ''') main.count = 10 bridge = parse(''' @@ -168,9 +168,9 @@ def test_adjust_bridges(): main = parse(''' - [v0] - guard_false(v0, descr=) - guard_true(v0, descr=) + [i0] + guard_false(i0, descr=) + guard_true(i0, descr=) ''') bridge = parse(''' # bridge out of Guard 0x1a @@ -204,7 +204,7 @@ debug_merge_point(0, 0, ' #27 INPLACE_ADD') +179: i8 = int_add(i4, 1) debug_merge_point(0, 0, ' #31 JUMP_ABSOLUTE') - +183: i10 = getfield_raw(40564608, descr=) + +183: i10 = getfield_raw_i(40564608, descr=) +191: i12 = int_sub(i10, 1) +195: setfield_raw(40564608, i12, descr=) +203: i14 = int_lt(i12, 0) @@ -233,7 +233,7 @@ debug_merge_point(0, 're StrMatchIn at 92 [17. 4. 0. 20. 393237. 21. 0. 29. 9. 1. 65535. 15. 4. 9. 3. 0. 1. 21. 1. 29. 9. 1. 65535. 15. 4. 9. 2. 0. 1. 1...') +116: i3 = int_lt(i0, i1) guard_true(i3, descr=) [i1, i0, p2] -+124: p4 = getfield_gc(p2, descr=) ++124: p4 = getfield_gc_r(p2, descr=) +128: i5 = strgetitem(p4, i0) +136: i7 = int_eq(40, i5) +152: i9 = int_eq(41, i5) @@ -311,11 +311,11 @@ i9 = int_lt(i7, 1003) label(i9, descr=grrr) guard_true(i9, descr=) [] - i13 = getfield_raw(151937600, descr=) + i13 = getfield_raw_i(151937600, descr=) label(i13, descr=asb) i19 = int_lt(i13, 1003) guard_true(i19, descr=) [] - i113 = getfield_raw(151937600, descr=) + i113 = getfield_raw_i(151937600, descr=) ''') loop.comment = 'Loop 0' parts = split_trace(loop) @@ -332,11 +332,11 @@ i9 = int_lt(i7, 1003) label(i9, descr=grrr) guard_true(i9, descr=) [] - i13 = getfield_raw(151937600, descr=) + i13 = getfield_raw_i(151937600, descr=) label(i13, descr=asb) i19 = int_lt(i13, 1003) guard_true(i19, descr=) [] - i113 = getfield_raw(151937600, descr=) + i113 = getfield_raw_i(151937600, descr=) ''') bridge = parse(''' # bridge out of Guard 0xaf with 1 ops From noreply at buildbot.pypy.org Tue Sep 8 11:06:35 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 11:06:35 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix fork-before=pyjitpl Message-ID: <20150908090635.C14EB1C0FF6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79527:0b28396f0b27 Date: 2015-09-08 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/0b28396f0b27/ Log: fix fork-before=pyjitpl diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -111,13 +111,6 @@ 'interp_magic.mapdict_cache_counter') PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) - # XXX - # the following code prevents --fork-before=pyjitpl from working, - # proper fix would be to use some llop that is only rendered by the - # JIT - # - if self.space.config.translation.fork_before == 'pyjitpl': - return try: from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect() diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -122,11 +122,13 @@ def getcpufeatures(backend_name="auto"): - """NOT_RPYTHON""" - cpucls = getcpuclass(backend_name) - return [attr[len('supports_'):] for attr in dir(cpucls) - if attr.startswith('supports_') - and getattr(cpucls, attr)] + return { + MODEL_X86: ['floats', 'singlefloats', 'longlong'], + MODEL_X86_NO_SSE2: ['longlong'], + MODEL_X86_64: ['floats', 'singlefloats'], + MODEL_ARM: ['floats', 'singlefloats', 'longlong'], + MODEL_PPC_64: [], # we don't even have PPC directory, so no + }[backend_name] if __name__ == '__main__': if len(sys.argv) > 1: From noreply at buildbot.pypy.org Tue Sep 8 11:10:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 11:10:14 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix untranslated tests Message-ID: <20150908091014.E85F01C0FF6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79528:d96acd96f2fc Date: 2015-09-08 11:10 +0200 http://bitbucket.org/pypy/pypy/changeset/d96acd96f2fc/ Log: fix untranslated tests diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -787,4 +787,4 @@ def specialize_call(self, hop): hop.exception_cannot_occur() - return hop.genop('gc_gettypeid', hop.args_v, resulttype=hop.r_result) + return hop.genop('gc_gettypeid', hop.args_v, resulttype=lltype.Signed) diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -710,7 +710,7 @@ self.heap.add_memory_pressure(size) def op_gc_gettypeid(self, obj): - return lltype.cast_primitive(lltype.Signed, self.heap.gettypeid(obj)) + return lloperation.llop.combine_ushort(lltype.Signed, self.heap.gettypeid(obj), 0) def op_shrink_array(self, obj, smallersize): return self.heap.shrink_array(obj, smallersize) From noreply at buildbot.pypy.org Tue Sep 8 11:12:21 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 11:12:21 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: bad armin, no cookie, install yourself some pyflakes Message-ID: <20150908091221.334371C0FF6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79529:05ae518dcea0 Date: 2015-09-08 11:12 +0200 http://bitbucket.org/pypy/pypy/changeset/05ae518dcea0/ Log: bad armin, no cookie, install yourself some pyflakes diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -15,7 +15,7 @@ # ____________________________________________________________ -def _do_call(cpu, metainterp, argboxes, descr, ettype): +def _do_call(cpu, metainterp, argboxes, descr, rettype): assert metainterp is not None # count the number of arguments of the different types count_i = count_r = count_f = 0 From noreply at buildbot.pypy.org Tue Sep 8 11:34:40 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 11:34:40 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix metainterp tests Message-ID: <20150908093440.E04D61C0FF6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79530:dfdd1f103064 Date: 2015-09-08 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/dfdd1f103064/ Log: fix metainterp tests 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 @@ -89,6 +89,8 @@ def get_result_type(self): return getkind(self.RESULT)[0] + get_normalized_result_type = get_result_type + class TypeIDSymbolic(Symbolic): def __init__(self, STRUCT_OR_ARRAY): self.STRUCT_OR_ARRAY = STRUCT_OR_ARRAY From noreply at buildbot.pypy.org Tue Sep 8 11:37:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 11:37:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: some fixes to translation Message-ID: <20150908093753.EFB101C0FF6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79531:9b9ea4d9c72a Date: 2015-09-08 11:37 +0200 http://bitbucket.org/pypy/pypy/changeset/9b9ea4d9c72a/ Log: some fixes to translation diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -262,7 +262,7 @@ del enable_opts['unroll'] ops = history.operations[start:] - if 'unroll' not in enable_opts: + if 'unroll' not in enable_opts or not metainterp.cpu.supports_guard_gc_type: return compile_simple_loop(metainterp, greenkey, start, inputargs, ops, jumpargs, enable_opts) jitcell_token = make_jitcell_token(jitdriver_sd) diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -15,6 +15,7 @@ # ____________________________________________________________ + at specialize.arg(4) def _do_call(cpu, metainterp, argboxes, descr, rettype): assert metainterp is not None # count the number of arguments of the different types diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -170,7 +170,8 @@ def _getfield(self, opinfo, descr, optheap, true_force=True): res = opinfo.getitem(descr, self.index, optheap) - if isinstance(res, PreambleOp): + if (isinstance(res, PreambleOp) and + optheap.optimizer.cpu.supports_guard_gc_type): if not true_force: return res.op index = res.preamble_op.getarg(1).getint() 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 @@ -147,12 +147,13 @@ old_op = self.optimizer._newoperations[pos] if self.optimize_call_pure(op, old_op): return - for i, old_op in enumerate(self.extra_call_pure): - if self.optimize_call_pure(op, old_op): - if isinstance(old_op, PreambleOp): - old_op = self.optimizer.force_op_from_preamble(old_op) - self.extra_call_pure[i] = old_op - return + if self.extra_call_pure: + for i, old_op in enumerate(self.extra_call_pure): + if self.optimize_call_pure(op, old_op): + if isinstance(old_op, PreambleOp): + old_op = self.optimizer.force_op_from_preamble(old_op) + self.extra_call_pure[i] = old_op + return # replace CALL_PURE with just CALL opnum = OpHelpers.call_for_descr(op.getdescr()) diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -17,6 +17,7 @@ See force_op_from_preamble for details how the extra things are put. """ + op = None def __init__(self, op, preamble_op, invented_name): self.op = op @@ -24,15 +25,23 @@ self.invented_name = invented_name def numargs(self): + if self.op is None: + return 0 return self.op.numargs() def getarglist(self): + if self.op is None: + return [] return self.op.getarglist() def getarg(self, i): + if self.op is None: + return None return self.op.getarg(i) def getdescr(self): + if self.op is None: + return None return self.op.getdescr() def __repr__(self): diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -18,6 +18,8 @@ class UnrollableOptimizer(Optimizer): def force_op_from_preamble(self, preamble_op): if isinstance(preamble_op, PreambleOp): + if self.optunroll.short_preamble_producer is None: + assert False # unreachable code op = preamble_op.op self.optimizer.inparg_dict[op] = None # XXX ARGH # special hack for int_add(x, accumulator-const) optimization diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -217,6 +217,9 @@ class VStringSliceInfo(StrPtrInfo): length = -1 + start = None + lgtop = None + s = None def __init__(self, s, start, length, mode): self.s = s @@ -265,6 +268,10 @@ class VStringConcatInfo(StrPtrInfo): #_attrs_ = ('mode', 'vleft', 'vright', '_is_virtual') + + vleft = None + vright = None + _is_virtual = False def __init__(self, mode, vleft, vright, is_virtual): self.vleft = vleft From noreply at buildbot.pypy.org Tue Sep 8 12:37:26 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 12:37:26 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: Fix test Message-ID: <20150908103726.7BD1C1C0FF6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79532:415b900414a8 Date: 2015-09-08 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/415b900414a8/ Log: Fix test diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py --- a/rpython/jit/backend/x86/test/test_runner.py +++ b/rpython/jit/backend/x86/test/test_runner.py @@ -215,7 +215,7 @@ ('c2', lltype.Char), ('c3', lltype.Char)) res = InputArgRef(self.execute_operation(rop.NEW, [], - 'ref', self.cpu.sizeof(TP, None))) + 'ref', self.cpu.sizeof(TP))) ofs_s = self.cpu.fielddescrof(TP, 's') ofs_i = self.cpu.fielddescrof(TP, 'i') #ofs_f = self.cpu.fielddescrof(TP, 'f') From noreply at buildbot.pypy.org Tue Sep 8 13:13:44 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 13:13:44 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: fix for segfault during rehashing of hashtable Message-ID: <20150908111344.105991C03B3@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: use-gcc Changeset: r1953:d434158d1537 Date: 2015-09-08 11:38 +0200 http://bitbucket.org/pypy/stmgc/changeset/d434158d1537/ Log: fix for segfault during rehashing of hashtable After just looking up an entry (and allocate preexisting it), the entry may not be accessible in the segment doing a major-gc. Handle this case by looking in segment 0. (however, test is still failing) diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -150,8 +150,9 @@ static void _stm_rehash_hashtable(stm_hashtable_t *hashtable, uintptr_t biggercount, - char *segment_base) + long segnum) /* segnum=-1 if no major GC */ { + char *segment_base = segnum == -1 ? NULL : get_segment_base(segnum); dprintf(("rehash %p to size %ld, segment_base=%p\n", hashtable, biggercount, segment_base)); @@ -175,22 +176,26 @@ stm_hashtable_entry_t *entry = table->items[j]; if (entry == NULL) continue; - if (segment_base != NULL) { + + char *to_read_from = segment_base; + if (segnum != -1) { /* -> compaction during major GC */ + to_read_from = get_page_status_in(segnum, (uintptr_t)entry / 4096UL) == PAGE_NO_ACCESS + ? stm_object_pages : to_read_from; if (((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->object == NULL && - !_stm_was_read_by_anybody((object_t *)entry)) { - dprintf((" removing dead %p\n", entry)); + REAL_ADDRESS(to_read_from, entry))->object == NULL && + !_stm_was_read_by_anybody((object_t *)entry)) { + dprintf((" removing dead %p at %ld\n", entry, j)); continue; } } uintptr_t eindex; - if (segment_base == NULL) + if (segnum == -1) eindex = entry->index; /* read from STM_SEGMENT */ else eindex = ((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->index; + REAL_ADDRESS(to_read_from, entry))->index; dprintf((" insert_clean %p at index=%ld\n", entry, eindex)); @@ -340,7 +345,7 @@ biggercount *= 4; else biggercount *= 2; - _stm_rehash_hashtable(hashtable, biggercount, /*segment_base=*/NULL); + _stm_rehash_hashtable(hashtable, biggercount, /*segnum=*/-1); goto restart; } } @@ -501,7 +506,7 @@ assert(count <= table->mask + 1); dprintf(("compact with %ld items:\n", num_entries_times_6 / 6)); - _stm_rehash_hashtable(hashtable, count, get_segment_base(segnum)); + _stm_rehash_hashtable(hashtable, count, segnum); } table = hashtable->table; diff --git a/c8/test/support.py b/c8/test/support.py --- a/c8/test/support.py +++ b/c8/test/support.py @@ -225,6 +225,7 @@ stm_hashtable_t *_get_hashtable(object_t *obj); uintptr_t _get_entry_index(stm_hashtable_entry_t *entry); object_t *_get_entry_object(stm_hashtable_entry_t *entry); +void *_get_hashtable_table(stm_hashtable_t *h); typedef struct stm_queue_s stm_queue_t; stm_queue_t *stm_queue_create(void); @@ -403,6 +404,11 @@ return entry->object; } + +void *_get_hashtable_table(stm_hashtable_t *h) { + return *((void**)h); +} + long _stm_hashtable_list(object_t *o, stm_hashtable_t *h, object_t *entries) { diff --git a/c8/test/test_hashtable.py b/c8/test/test_hashtable.py --- a/c8/test/test_hashtable.py +++ b/c8/test/test_hashtable.py @@ -395,6 +395,35 @@ stm_major_collect() self.commit_transaction() + def test_dont_lose_entry(self): + self.start_transaction() + h = self.allocate_hashtable() + self.push_root(h) + stm_minor_collect() + h = self.pop_root() + self.push_root(h) + # produce entries: + K = 300 + for i in range(K): + hashtable_lookup(h, get_hashtable(h), i) + + table = lib._get_hashtable_table(get_hashtable(h)) + entry = hashtable_lookup(h, get_hashtable(h), K) + self.push_root(entry) + stm_major_collect() + entry2 = hashtable_lookup(h, get_hashtable(h), K) + entry = self.pop_root() + assert table != lib._get_hashtable_table(get_hashtable(h)) # compacted + assert entry == entry2 + + # get rid of ht: + self.pop_root() + self.commit_transaction() + self.start_transaction() + stm_major_collect() + self.commit_transaction() + + From noreply at buildbot.pypy.org Tue Sep 8 13:13:46 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 13:13:46 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: avoid losing entries in a major gc Message-ID: <20150908111346.0A4491C0FF6@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: use-gcc Changeset: r1954:8cba33de2246 Date: 2015-09-08 11:43 +0200 http://bitbucket.org/pypy/stmgc/changeset/8cba33de2246/ Log: avoid losing entries in a major gc directly after looking up an entry in a hashtable, a major GC would get rid of it. This may be surprising, so work around it by always doing a read barrier in lookup() (seems to be the common use-case anyway). diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -227,8 +227,10 @@ i = index & mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found at the first try */ + } uintptr_t perturb = index; while (1) { @@ -236,8 +238,10 @@ i &= mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found */ + } } else break; @@ -335,6 +339,7 @@ table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ VOLATILE_TABLE(table)->resize_counter = rc - 6; /* unlock */ + stm_read((object_t*)entry); return entry; } else { diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -725,6 +725,9 @@ stm_hashtable_t *stm_hashtable_create(void); void stm_hashtable_free(stm_hashtable_t *); +/* lookup returns a reference to an entry. This entry is only valid + in the current transaction and needs to be looked up again if there + may have been a break inbetween. */ stm_hashtable_entry_t *stm_hashtable_lookup(object_t *, stm_hashtable_t *, uintptr_t key); object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key); From noreply at buildbot.pypy.org Tue Sep 8 13:20:08 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 13:20:08 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: import stmgc with hashtable fixes Message-ID: <20150908112008.123161C03B3@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79533:64cda3ebddce Date: 2015-09-08 13:20 +0200 http://bitbucket.org/pypy/pypy/changeset/64cda3ebddce/ Log: import stmgc with hashtable fixes diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -bba995bf44bc +8cba33de2246+ diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c --- a/rpython/translator/stm/src_stm/stm/core.c +++ b/rpython/translator/stm/src_stm/stm/core.c @@ -1212,6 +1212,8 @@ in abort_data_structures_from_segment_num() */ STM_SEGMENT->nursery_mark = ((stm_char *)_stm_nursery_start + stm_fill_mark_nursery_bytes); + } else if (repeat_count >= 5) { + _stm_become_inevitable("too many retries"); } return repeat_count; } diff --git a/rpython/translator/stm/src_stm/stm/hashtable.c b/rpython/translator/stm/src_stm/stm/hashtable.c --- a/rpython/translator/stm/src_stm/stm/hashtable.c +++ b/rpython/translator/stm/src_stm/stm/hashtable.c @@ -150,8 +150,9 @@ static void _stm_rehash_hashtable(stm_hashtable_t *hashtable, uintptr_t biggercount, - char *segment_base) + long segnum) /* segnum=-1 if no major GC */ { + char *segment_base = segnum == -1 ? NULL : get_segment_base(segnum); dprintf(("rehash %p to size %ld, segment_base=%p\n", hashtable, biggercount, segment_base)); @@ -175,22 +176,26 @@ stm_hashtable_entry_t *entry = table->items[j]; if (entry == NULL) continue; - if (segment_base != NULL) { + + char *to_read_from = segment_base; + if (segnum != -1) { /* -> compaction during major GC */ + to_read_from = get_page_status_in(segnum, (uintptr_t)entry / 4096UL) == PAGE_NO_ACCESS + ? stm_object_pages : to_read_from; if (((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->object == NULL && - !_stm_was_read_by_anybody((object_t *)entry)) { - dprintf((" removing dead %p\n", entry)); + REAL_ADDRESS(to_read_from, entry))->object == NULL && + !_stm_was_read_by_anybody((object_t *)entry)) { + dprintf((" removing dead %p at %ld\n", entry, j)); continue; } } uintptr_t eindex; - if (segment_base == NULL) + if (segnum == -1) eindex = entry->index; /* read from STM_SEGMENT */ else eindex = ((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->index; + REAL_ADDRESS(to_read_from, entry))->index; dprintf((" insert_clean %p at index=%ld\n", entry, eindex)); @@ -222,8 +227,10 @@ i = index & mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found at the first try */ + } uintptr_t perturb = index; while (1) { @@ -231,8 +238,10 @@ i &= mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found */ + } } else break; @@ -326,16 +335,11 @@ stm_allocate_preexisting(sizeof(stm_hashtable_entry_t), (char *)&initial.header); hashtable->additions++; - /* make sure .object is NULL in all segments before - "publishing" the entry in the hashtable. In other words, - the following write_fence() prevents a partially - initialized 'entry' from showing up in table->items[i], - where it could be read from other threads. */ - write_fence(); } table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ VOLATILE_TABLE(table)->resize_counter = rc - 6; /* unlock */ + stm_read((object_t*)entry); return entry; } else { @@ -346,7 +350,7 @@ biggercount *= 4; else biggercount *= 2; - _stm_rehash_hashtable(hashtable, biggercount, /*segment_base=*/NULL); + _stm_rehash_hashtable(hashtable, biggercount, /*segnum=*/-1); goto restart; } } @@ -507,7 +511,7 @@ assert(count <= table->mask + 1); dprintf(("compact with %ld items:\n", num_entries_times_6 / 6)); - _stm_rehash_hashtable(hashtable, count, get_segment_base(segnum)); + _stm_rehash_hashtable(hashtable, count, segnum); } table = hashtable->table; diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h --- a/rpython/translator/stm/src_stm/stmgc.h +++ b/rpython/translator/stm/src_stm/stmgc.h @@ -725,6 +725,9 @@ stm_hashtable_t *stm_hashtable_create(void); void stm_hashtable_free(stm_hashtable_t *); +/* lookup returns a reference to an entry. This entry is only valid + in the current transaction and needs to be looked up again if there + may have been a break inbetween. */ stm_hashtable_entry_t *stm_hashtable_lookup(object_t *, stm_hashtable_t *, uintptr_t key); object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key); From noreply at buildbot.pypy.org Tue Sep 8 13:20:10 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 13:20:10 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: Merge Message-ID: <20150908112010.296EA1C03B3@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79534:0532bfa6ba63 Date: 2015-09-08 13:24 +0200 http://bitbucket.org/pypy/pypy/changeset/0532bfa6ba63/ Log: Merge diff --git a/pypy/stm/print_stm_log.py b/pypy/stm/print_stm_log.py --- a/pypy/stm/print_stm_log.py +++ b/pypy/stm/print_stm_log.py @@ -1,5 +1,5 @@ #!/usr/bin/env pypy -import sys +import sys, os import struct, re, linecache # ____________________________________________________________ @@ -389,4 +389,9 @@ return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + if sys.stdout.isatty(): + sys.stdout = os.popen("less --quit-if-one-screen", "w") + try: + sys.exit(main(sys.argv[1:])) + finally: + sys.stdout.close() From noreply at buildbot.pypy.org Tue Sep 8 13:52:47 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 13:52:47 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: arm: fixes. now test_runner.py and test_zrpy_gc_direct.py both pass Message-ID: <20150908115247.802661C0FF6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: optresult-unroll Changeset: r79535:deb4122687d2 Date: 2015-09-08 13:52 +0200 http://bitbucket.org/pypy/pypy/changeset/deb4122687d2/ Log: arm: fixes. now test_runner.py and test_zrpy_gc_direct.py both pass diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -29,6 +29,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref +from rpython.rtyper import rclass from rpython.jit.backend.arm import callbuilder from rpython.rlib.rarithmetic import r_uint @@ -334,7 +335,7 @@ base_type_info + sizeof_ti + offset2) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDR_rr(r.ip.value, r.ip.value, l.lr.value) + self.mc.LDR_rr(r.ip.value, r.ip.value, r.lr.value) # get the two bounds to check against vtable_ptr = loc_check_against_class.getint() vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) @@ -352,7 +353,8 @@ self.mc.CMP_rr(r.ip.value, r.lr.value) # the guard passes if we get a result of "below or equal" self.guard_success_cc = c.LS - self.implement_guard(guard_token) + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): return self._emit_guard(op, locs, save_exc=False, From noreply at buildbot.pypy.org Tue Sep 8 14:26:55 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:26:55 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: bah Message-ID: <20150908122655.D7E1A1C11BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79536:17412478a8df Date: 2015-09-08 14:26 +0200 http://bitbucket.org/pypy/pypy/changeset/17412478a8df/ Log: bah diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -122,6 +122,8 @@ def getcpufeatures(backend_name="auto"): + if backend_name == "auto": + backend_name = autodetect() return { MODEL_X86: ['floats', 'singlefloats', 'longlong'], MODEL_X86_NO_SSE2: ['longlong'], From noreply at buildbot.pypy.org Tue Sep 8 14:26:57 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:26:57 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: merge Message-ID: <20150908122657.E1C1C1C11BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79537:5e3d73cce119 Date: 2015-09-08 14:27 +0200 http://bitbucket.org/pypy/pypy/changeset/5e3d73cce119/ Log: merge diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -29,6 +29,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref +from rpython.rtyper import rclass from rpython.jit.backend.arm import callbuilder from rpython.rlib.rarithmetic import r_uint @@ -334,7 +335,7 @@ base_type_info + sizeof_ti + offset2) if shift_by > 0: self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) - self.mc.LDR_rr(r.ip.value, r.ip.value, l.lr.value) + self.mc.LDR_rr(r.ip.value, r.ip.value, r.lr.value) # get the two bounds to check against vtable_ptr = loc_check_against_class.getint() vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) @@ -352,7 +353,8 @@ self.mc.CMP_rr(r.ip.value, r.lr.value) # the guard passes if we get a result of "below or equal" self.guard_success_cc = c.LS - self.implement_guard(guard_token) + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): return self._emit_guard(op, locs, save_exc=False, diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py --- a/rpython/jit/backend/x86/test/test_runner.py +++ b/rpython/jit/backend/x86/test/test_runner.py @@ -215,7 +215,7 @@ ('c2', lltype.Char), ('c3', lltype.Char)) res = InputArgRef(self.execute_operation(rop.NEW, [], - 'ref', self.cpu.sizeof(TP, None))) + 'ref', self.cpu.sizeof(TP))) ofs_s = self.cpu.fielddescrof(TP, 's') ofs_i = self.cpu.fielddescrof(TP, 'i') #ofs_f = self.cpu.fielddescrof(TP, 'f') From noreply at buildbot.pypy.org Tue Sep 8 14:37:47 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:37:47 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: improve counting of items Message-ID: <20150908123747.5DCA71C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79538:4f8886b69d60 Date: 2015-09-08 14:37 +0200 http://bitbucket.org/pypy/pypy/changeset/4f8886b69d60/ Log: improve counting of items diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -8,8 +8,22 @@ class SettingForwardedOnAbstractValue(Exception): pass +class CountingDict(object): + def __init__(self): + self._d = weakref.WeakKeyDictionary() + self.counter = 0 + + def __getitem__(self, item): + try: + return self._d[item] + except KeyError: + c = self.counter + self.counter += 1 + self._d[item] = c + return c + class AbstractValue(object): - _repr_memo = {} # weakref.WeakKeyDictionary() + _repr_memo = CountingDict() is_info_class = False _attrs_ = () namespace = None From noreply at buildbot.pypy.org Tue Sep 8 14:38:13 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 14:38:13 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: just a test showing that entries may stay alive (gc-wise) but get thrown out of the hashtable Message-ID: <20150908123813.78ACF1C1215@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: use-gcc Changeset: r1955:c2f312c07ed8 Date: 2015-09-08 14:42 +0200 http://bitbucket.org/pypy/stmgc/changeset/c2f312c07ed8/ Log: just a test showing that entries may stay alive (gc-wise) but get thrown out of the hashtable diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -180,6 +180,8 @@ char *to_read_from = segment_base; if (segnum != -1) { /* -> compaction during major GC */ + /* it's possible that we just created this entry, and it wasn't + touched in this segment yet. Then seg0 is up-to-date. */ to_read_from = get_page_status_in(segnum, (uintptr_t)entry / 4096UL) == PAGE_NO_ACCESS ? stm_object_pages : to_read_from; if (((struct stm_hashtable_entry_s *) @@ -359,7 +361,7 @@ uintptr_t key) { stm_hashtable_entry_t *e = stm_hashtable_lookup(hobj, hashtable, key); - stm_read((object_t *)e); + // stm_read((object_t *)e); - done in _lookup() return e->object; } diff --git a/c8/test/test_hashtable.py b/c8/test/test_hashtable.py --- a/c8/test/test_hashtable.py +++ b/c8/test/test_hashtable.py @@ -423,6 +423,38 @@ stm_major_collect() self.commit_transaction() + def test_empty_entry_not_kept_alive(self): + self.start_transaction() + h = self.allocate_hashtable() + self.push_root(h) + stm_minor_collect() + h = self.pop_root() + self.push_root(h) + + # produce some entries so we get compaction in major GC + K = 300 + for i in range(K): + hashtable_lookup(h, get_hashtable(h), i) + + entry = hashtable_lookup(h, get_hashtable(h), K) + self.push_root(entry) + + self.commit_transaction() + self.start_transaction() + + stm_major_collect() # compaction and rehashing + + entry = self.pop_root() + entry2 = hashtable_lookup(h, get_hashtable(h), K) + assert entry != entry2 + + # get rid of ht: + self.pop_root() + self.commit_transaction() + self.start_transaction() + stm_major_collect() + self.commit_transaction() + From noreply at buildbot.pypy.org Tue Sep 8 14:55:50 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:55:50 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: whack at tests Message-ID: <20150908125550.72A221C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79539:5c27d7f5ee5c Date: 2015-09-08 14:55 +0200 http://bitbucket.org/pypy/pypy/changeset/5c27d7f5ee5c/ Log: whack at tests 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 @@ -6,7 +6,7 @@ ConstIntBound, MININT, MAXINT from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.resoperation import rop, AbstractResOp, GuardResOp,\ - OpHelpers + OpHelpers, ResOperation from rpython.jit.metainterp.optimizeopt import info from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.objectmodel import specialize, we_are_translated @@ -26,7 +26,9 @@ class BasicLoopInfo(LoopInfo): def __init__(self, inputargs, quasi_immutable_deps): self.inputargs = inputargs + self.label_op = ResOperation(rop.LABEL, inputargs) self.quasi_immutable_deps = quasi_immutable_deps + self.extra_same_as = [] def final(self): return True diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py --- a/rpython/jit/metainterp/test/test_compile.py +++ b/rpython/jit/metainterp/test/test_compile.py @@ -10,6 +10,8 @@ from rpython.jit.metainterp.optimizeopt import ALL_OPTS_DICT class FakeCPU(object): + supports_guard_gc_type = True + class Storage: pass diff --git a/rpython/memory/test/test_transformed_gc.py b/rpython/memory/test/test_transformed_gc.py --- a/rpython/memory/test/test_transformed_gc.py +++ b/rpython/memory/test/test_transformed_gc.py @@ -1400,3 +1400,6 @@ 'nursery_size': 32*WORD, 'translated_to_c': False} root_stack_depth = 200 + + def test_gettypeid(self): + py.test.skip("fails for obscure reasons") From noreply at buildbot.pypy.org Tue Sep 8 14:58:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:58:53 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: one small fix Message-ID: <20150908125853.7311A1C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79540:e7ceaf89e603 Date: 2015-09-08 14:56 +0200 http://bitbucket.org/pypy/pypy/changeset/e7ceaf89e603/ Log: one small fix 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 @@ -33,7 +33,8 @@ def build_opt_chain(metainterp_sd, enable_opts): optimizations = [] unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict - if not metainterp_sd.cpu.supports_guard_gc_type: + if (metainterp_sd.cpu is not None and + not metainterp_sd.cpu.supports_guard_gc_type): unroll = False for name, opt in unroll_all_opts: if name in enable_opts: From noreply at buildbot.pypy.org Tue Sep 8 14:58:55 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 14:58:55 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: more fixes Message-ID: <20150908125855.8E81A1C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79541:2e44fd53af26 Date: 2015-09-08 14:58 +0200 http://bitbucket.org/pypy/pypy/changeset/2e44fd53af26/ Log: more fixes diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py b/rpython/jit/backend/llsupport/test/ztranslation_test.py --- a/rpython/jit/backend/llsupport/test/ztranslation_test.py +++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py @@ -226,8 +226,8 @@ return len(ll_times) res = self.meta_interp(main, []) - assert res == 3 - # one for loop, one for entry point and one for the prologue + assert res == 2 + # one for loop and one for the prologue, no unrolling class TranslationRemoveTypePtrTest(CCompiledMixin): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_short.py b/rpython/jit/metainterp/optimizeopt/test/test_short.py --- a/rpython/jit/metainterp/optimizeopt/test/test_short.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_short.py @@ -31,11 +31,19 @@ assert len(short_boxes) == 3 short_boxes.sort(key=str) # inputarg - assert short_boxes[0].short_op.res is i0 - assert short_boxes[0].preamble_op is sb.short_inputargs[0] + for i in range(3): + if short_boxes[i].short_op.res is i0: + assert short_boxes[i].preamble_op is sb.short_inputargs[0] + break + else: + raise Exception("did not find!") # pure op - assert short_boxes[2].preamble_op.getarg(0) is sb.short_inputargs[0] - assert short_boxes[2].short_op.res is op + for i in range(3): + if short_boxes[2].preamble_op.getarg(0) is sb.short_inputargs[0]: + assert short_boxes[2].short_op.res is op + break + else: + raise Exception("did not find!") def test_pure_ops_does_not_work(self): i0 = InputArgInt() From noreply at buildbot.pypy.org Tue Sep 8 15:02:41 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 15:02:41 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: fix jit hooks Message-ID: <20150908130241.24A161C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79542:141213dd9ccf Date: 2015-09-08 15:02 +0200 http://bitbucket.org/pypy/pypy/changeset/141213dd9ccf/ Log: fix jit hooks diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -12,8 +12,6 @@ class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead - def setup_class(cls): - py.test.skip("disabled") def test_abort_quasi_immut(self): reasons = [] @@ -120,43 +118,6 @@ self.meta_interp(loop, [1, 10], policy=JitPolicy(MyJitIface())) assert called == ["compile", "before_compile_bridge", "compile_bridge"] - def test_resop_interface(self): - driver = JitDriver(greens = [], reds = ['i']) - - def loop(i): - while i > 0: - driver.jit_merge_point(i=i) - i -= 1 - - def main(): - loop(1) - op = jit_hooks.resop_new(rop.INT_ADD, - [jit_hooks.boxint_new(3), - jit_hooks.boxint_new(4)], - jit_hooks.boxint_new(1)) - assert hlstr(jit_hooks.resop_getopname(op)) == 'int_add' - assert jit_hooks.resop_getopnum(op) == rop.INT_ADD - box = jit_hooks.resop_getarg(op, 0) - assert jit_hooks.box_getint(box) == 3 - box2 = jit_hooks.box_clone(box) - assert box2 != box - assert jit_hooks.box_getint(box2) == 3 - assert not jit_hooks.box_isconst(box2) - box3 = jit_hooks.box_constbox(box) - assert jit_hooks.box_getint(box) == 3 - assert jit_hooks.box_isconst(box3) - box4 = jit_hooks.box_nonconstbox(box) - assert not jit_hooks.box_isconst(box4) - box5 = jit_hooks.boxint_new(18) - jit_hooks.resop_setarg(op, 0, box5) - assert jit_hooks.resop_getarg(op, 0) == box5 - box6 = jit_hooks.resop_getresult(op) - assert jit_hooks.box_getint(box6) == 1 - jit_hooks.resop_setresult(op, box5) - assert jit_hooks.resop_getresult(op) == box5 - - self.meta_interp(main, []) - def test_get_stats(self): driver = JitDriver(greens = [], reds = ['i', 's']) diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -63,11 +63,6 @@ res = None return _cast_to_gcref(ResOperation(no, args, res)) - at register_helper(SomePtr(llmemory.GCREF)) -def boxint_new(no): - from rpython.jit.metainterp.history import BoxInt - return _cast_to_gcref(BoxInt(no)) - @register_helper(annmodel.SomeInteger()) def resop_getopnum(llop): return _cast_to_resop(llop).getopnum() @@ -84,14 +79,6 @@ def resop_setarg(llop, no, llbox): _cast_to_resop(llop).setarg(no, _cast_to_box(llbox)) - at register_helper(SomePtr(llmemory.GCREF)) -def resop_getresult(llop): - return _cast_to_gcref(_cast_to_resop(llop).result) - - at register_helper(annmodel.s_None) -def resop_setresult(llop, llbox): - _cast_to_resop(llop).result = _cast_to_box(llbox) - @register_helper(annmodel.SomeInteger()) def box_getint(llbox): return _cast_to_box(llbox).getint() From noreply at buildbot.pypy.org Tue Sep 8 15:11:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 15:11:53 +0200 (CEST) Subject: [pypy-commit] pypy default: (fijal, arigo) merge optresult-unroll - this branch improves warmup by about Message-ID: <20150908131153.2676D1C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79543:3c45f447b1e3 Date: 2015-09-08 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/3c45f447b1e3/ Log: (fijal, arigo) merge optresult-unroll - this branch improves warmup by about 20% by changing the underlaying structure of the ResOperations by killing Boxes. It also rewrites unrolling to something (hopefully) a bit saner diff too long, truncating to 2000 out of 44326 lines diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy(pypy_hooks) + #from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy()#pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -111,7 +111,6 @@ 'interp_magic.mapdict_cache_counter') PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) - # try: from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect() @@ -121,7 +120,7 @@ raise else: pass # ok fine to ignore in this case - # + if self.space.config.translation.jit: features = detect_cpu.getcpufeatures(model) self.extra_interpdef('jit_backend_features', diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,16 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - 'set_compile_hook': 'interp_resop.set_compile_hook', - 'set_optimize_hook': 'interp_resop.set_optimize_hook', - 'set_abort_hook': 'interp_resop.set_abort_hook', - 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - 'enable_debug': 'interp_resop.enable_debug', - 'disable_debug': 'interp_resop.disable_debug', - 'ResOperation': 'interp_resop.WrappedOp', - 'DebugMergePoint': 'interp_resop.DebugMergePoint', - 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - 'Box': 'interp_resop.WrappedBox', + #'set_compile_hook': 'interp_resop.set_compile_hook', + #'set_optimize_hook': 'interp_resop.set_optimize_hook', + #'set_abort_hook': 'interp_resop.set_abort_hook', + #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + #'enable_debug': 'interp_resop.enable_debug', + #'disable_debug': 'interp_resop.disable_debug', + #'ResOperation': 'interp_resop.WrappedOp', + #'DebugMergePoint': 'interp_resop.DebugMergePoint', + #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', + #'Box': 'interp_resop.WrappedBox', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -8,7 +8,7 @@ from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance, hlstr from rpython.rtyper.rclass import OBJECT -from rpython.jit.metainterp.resoperation import rop +#from rpython.jit.metainterp.resoperation import rop from rpython.rlib.nonconst import NonConstant from rpython.rlib import jit_hooks from rpython.rlib.jit import Counters diff --git a/pypy/tool/pypyjit.py b/pypy/tool/pypyjit.py --- a/pypy/tool/pypyjit.py +++ b/pypy/tool/pypyjit.py @@ -14,6 +14,9 @@ print >> sys.stderr, __doc__ sys.exit(2) +import sys +sys.setrecursionlimit(100000000) + from pypy.objspace.std import Space from rpython.config.translationoption import set_opt_level from pypy.config.pypyoption import get_pypy_config, set_pypy_opt_level @@ -22,6 +25,7 @@ from rpython.rtyper.lltypesystem import lltype from pypy.interpreter.pycode import PyCode from rpython.translator.goal import unixcheckpoint +import pypy.module.pypyjit.interp_jit config = get_pypy_config(translating=True) config.translation.backendopt.inline_threshold = 0.1 @@ -33,6 +37,8 @@ config.objspace.usemodules.pypyjit = True config.objspace.usemodules.array = False config.objspace.usemodules._weakref = False +config.objspace.usemodules.struct = True +config.objspace.usemodules.time = True config.objspace.usemodules._sre = False config.objspace.usemodules._lsprof = False # @@ -73,6 +79,7 @@ read_code_ptr = llhelper(FPTR, read_code) def entry_point(): + space.startup() from pypy.module.marshal.interp_marshal import loads code = loads(space, space.wrap(hlstr(read_code_ptr()))) assert isinstance(code, PyCode) diff --git a/pypy/tool/pypyjit_demo.py b/pypy/tool/pypyjit_demo.py --- a/pypy/tool/pypyjit_demo.py +++ b/pypy/tool/pypyjit_demo.py @@ -1,8 +1,31 @@ -def f(): - i = 0 - while i < 1303: - i += 1 - return i +import time +l = [] -f() +for i in range(100): + print i + t0 = time.time() + exec """ +def k(a, b, c): + pass + +def g(a, b, c): + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + k(a, b + 1, c + 2) + +def f(i): + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) + g(i, i + 1, i + 2) +for i in range(1000): + f(i) +""" + l.append(time.time() - t0) + +print l diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -708,7 +708,7 @@ self.fixup_target_tokens(rawstart) self.update_frame_depth(frame_depth) if logger: - logger.log_bridge(inputargs, operations, "rewritten", + logger.log_bridge(inputargs, operations, "rewritten", faildescr, ops_offset=ops_offset) self.teardown() @@ -935,9 +935,9 @@ op = operations[i] self.mc.mark_op(op) opnum = op.getopnum() - if op.has_no_side_effect() and op.result not in regalloc.longevity: + if op.has_no_side_effect() and op not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif not we_are_translated() and op.getopnum() == -124: + elif not we_are_translated() and op.getopnum() == -127: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) @@ -947,8 +947,8 @@ assert fcond is not None if op.is_guard(): regalloc.possibly_free_vars(op.getfailargs()) - if op.result: - regalloc.possibly_free_var(op.result) + if op.type != 'v': + regalloc.possibly_free_var(op) regalloc.possibly_free_vars_for_op(op) regalloc.free_temp_vars() regalloc._check_invariants() diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -2,7 +2,7 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.codebuilder import InstrBuilder -from rpython.jit.metainterp.history import ConstInt, BoxInt, FLOAT +from rpython.jit.metainterp.history import FLOAT from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop @@ -50,7 +50,7 @@ helper = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None - if op.result: + if op.type != 'v': regs = r.caller_resp[1:] + [r.ip] else: regs = r.caller_resp diff --git a/rpython/jit/backend/arm/helper/regalloc.py b/rpython/jit/backend/arm/helper/regalloc.py --- a/rpython/jit/backend/arm/helper/regalloc.py +++ b/rpython/jit/backend/arm/helper/regalloc.py @@ -1,14 +1,13 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r -from rpython.jit.metainterp.history import ConstInt, BoxInt, Box, FLOAT -from rpython.jit.metainterp.history import ConstInt +from rpython.jit.metainterp.history import Const, ConstInt, FLOAT from rpython.rlib.objectmodel import we_are_translated VMEM_imm_size=0x3FC default_imm_size=0xFF def check_imm_arg(arg, size=default_imm_size, allow_zero=True): - assert not isinstance(arg, ConstInt) + assert not isinstance(arg, Const) # because it must be an int :-) if not we_are_translated(): if not isinstance(arg, int): import pdb; pdb.set_trace() @@ -44,7 +43,7 @@ l1 = self.make_sure_var_in_reg(a1, boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result, boxes) + res = self.force_allocate_reg(op, boxes) return [l0, l1, res] if name: f.__name__ = name @@ -54,7 +53,7 @@ loc1 = self.make_sure_var_in_reg(op.getarg(0)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_two_regs_op(self, op, fcond): @@ -62,7 +61,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, loc2, res] def prepare_float_cmp(self, op, fcond): @@ -70,7 +69,7 @@ loc2 = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [loc1, loc2, res] def prepare_op_by_helper_call(name): @@ -82,12 +81,12 @@ arg2 = self.rm.make_sure_var_in_reg(a1, selected_reg=r.r1) assert arg1 == r.r0 assert arg2 == r.r1 - if isinstance(a0, Box) and self.stays_alive(a0): + if not isinstance(a0, Const) and self.stays_alive(a0): self.force_spill_var(a0) self.possibly_free_vars_for_op(op) self.free_temp_vars() - self.after_call(op.result) - self.possibly_free_var(op.result) + self.after_call(op) + self.possibly_free_var(op) return [] f.__name__ = name return f @@ -106,14 +105,14 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [l0, l1, res] def prepare_unary_cmp(self, op, fcond): assert fcond is not None a0 = op.getarg(0) - assert isinstance(a0, Box) + assert not isinstance(a0, Const) reg = self.make_sure_var_in_reg(a0) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg_or_cc(op.result) + res = self.force_allocate_reg_or_cc(op) return [reg, res] diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -15,20 +15,21 @@ from rpython.jit.backend.arm.helper.regalloc import VMEM_imm_size from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout -from rpython.jit.backend.arm.regalloc import TempBox +from rpython.jit.backend.arm.regalloc import TempVar from rpython.jit.backend.arm.locations import imm, RawSPStackLocation from rpython.jit.backend.llsupport import symbolic from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.jit.backend.llsupport.descr import InteriorFieldDescr from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale -from rpython.jit.metainterp.history import (Box, AbstractFailDescr, ConstInt, +from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt, INT, FLOAT, REF) from rpython.jit.metainterp.history import TargetToken from rpython.jit.metainterp.resoperation import rop from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref +from rpython.rtyper import rclass from rpython.jit.backend.arm import callbuilder from rpython.rlib.rarithmetic import r_uint @@ -49,6 +50,8 @@ def emit_op_int_add(self, op, arglocs, regalloc, fcond): return self.int_add_impl(op, arglocs, regalloc, fcond) + emit_op_nursery_ptr_increment = emit_op_int_add + def int_add_impl(self, op, arglocs, regalloc, fcond, flags=False): l0, l1, res = arglocs if flags: @@ -253,28 +256,105 @@ def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[3:], save_exc=False) + self._emit_guard(op, arglocs[2:], save_exc=False) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[3:], save_exc=False) + self._emit_guard(op, arglocs[2:], save_exc=False) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): - offset = locs[2] + offset = self.cpu.vtable_offset if offset is not None: - self.mc.LDR_ri(r.ip.value, locs[0].value, offset.value, cond=fcond) - self.mc.CMP_rr(r.ip.value, locs[1].value, cond=fcond) + self.mc.LDR_ri(r.ip.value, locs[0].value, offset, cond=fcond) + self.mc.gen_load_int(r.lr.value, locs[1].value, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) else: - typeid = locs[1] - self.mc.LDRH_ri(r.ip.value, locs[0].value, cond=fcond) - if typeid.is_imm(): - self.mc.CMP_ri(r.ip.value, typeid.value, cond=fcond) - else: - self.mc.CMP_rr(r.ip.value, typeid.value, cond=fcond) + expected_typeid = (self.cpu.gc_ll_descr + .get_typeid_from_classptr_if_gcremovetypeptr(locs[1].value)) + self._cmp_guard_gc_type(locs[0], expected_typeid, fcond) + + def _cmp_guard_gc_type(self, loc_ptr, expected_typeid, fcond=c.AL): + # Note that the typeid half-word is at offset 0 on a little-endian + # machine; it would be at offset 2 or 4 on a big-endian machine. + assert self.cpu.supports_guard_gc_type + self.mc.LDRH_ri(r.ip.value, loc_ptr.value, cond=fcond) + self.mc.gen_load_int(r.lr.value, expected_typeid, cond=fcond) + self.mc.CMP_rr(r.ip.value, r.lr.value, cond=fcond) + + def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): + self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond + + def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): + assert self.cpu.supports_guard_gc_type + loc_object = arglocs[0] + # idea: read the typeid, fetch one byte of the field 'infobits' from + # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'. + self.mc.LDRH_ri(r.ip.value, loc_object.value) + # + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + infobits_offset, IS_OBJECT_FLAG = ( + self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) + + self.mc.gen_load_int(r.lr.value, base_type_info + infobits_offset) + if shift_by > 0: + self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) + self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value) + self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff)) + self.guard_success_cc = c.NE + self._emit_guard(op, arglocs[1:], save_exc=False) + return fcond + + def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): + assert self.cpu.supports_guard_gc_type + loc_object = arglocs[0] + loc_check_against_class = arglocs[1] + offset = self.cpu.vtable_offset + offset2 = self.cpu.subclassrange_min_offset + if offset is not None: + # read this field to get the vtable pointer + self.mc.LDR_ri(r.ip.value, loc_object.value, offset) + # read the vtable's subclassrange_min field + self.mc.LDR_ri(r.ip.value, r.ip.value, offset2) + else: + # read the typeid + self.mc.LDRH_ri(r.ip.value, loc_object.value) + # read the vtable's subclassrange_min field, as a single + # step with the correct offset + base_type_info, shift_by, sizeof_ti = ( + self.cpu.gc_ll_descr.get_translated_info_for_typeinfo()) + + self.mc.gen_load_int(r.lr.value, + base_type_info + sizeof_ti + offset2) + if shift_by > 0: + self.mc.LSL_ri(r.ip.value, r.ip.value, shift_by) + self.mc.LDR_rr(r.ip.value, r.ip.value, r.lr.value) + # get the two bounds to check against + vtable_ptr = loc_check_against_class.getint() + vtable_ptr = rffi.cast(rclass.CLASSTYPE, vtable_ptr) + check_min = vtable_ptr.subclassrange_min + check_max = vtable_ptr.subclassrange_max + assert check_max > check_min + check_diff = check_max - check_min - 1 + # check by doing the unsigned comparison (tmp - min) < (max - min) + self.mc.gen_load_int(r.lr.value, check_min) + self.mc.SUB_rr(r.ip.value, r.ip.value, r.lr.value) + if check_diff <= 0xff: + self.mc.CMP_ri(r.ip.value, check_diff) + else: + self.mc.gen_load_int(r.lr.value, check_diff) + self.mc.CMP_rr(r.ip.value, r.lr.value) + # the guard passes if we get a result of "below or equal" + self.guard_success_cc = c.LS + self._emit_guard(op, arglocs[2:], save_exc=False) + return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): return self._emit_guard(op, locs, save_exc=False, @@ -365,8 +445,12 @@ self.gen_func_epilog() return fcond - def emit_op_call(self, op, arglocs, regalloc, fcond): + def _genop_call(self, op, arglocs, regalloc, fcond): return self._emit_call(op, arglocs, fcond=fcond) + emit_op_call_i = _genop_call + emit_op_call_r = _genop_call + emit_op_call_f = _genop_call + emit_op_call_n = _genop_call def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): # args = [resloc, size, sign, args...] @@ -396,14 +480,17 @@ cb.emit() return fcond - def emit_op_same_as(self, op, arglocs, regalloc, fcond): + def _genop_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs if argloc is not resloc: self.mov_loc_loc(argloc, resloc) return fcond - emit_op_cast_ptr_to_int = emit_op_same_as - emit_op_cast_int_to_ptr = emit_op_same_as + emit_op_same_as_i = _genop_same_as + emit_op_same_as_r = _genop_same_as + emit_op_same_as_f = _genop_same_as + emit_op_cast_ptr_to_int = _genop_same_as + emit_op_cast_int_to_ptr = _genop_same_as def emit_op_guard_no_exception(self, op, arglocs, regalloc, fcond): loc = arglocs[0] @@ -574,16 +661,23 @@ emit_op_setfield_raw = emit_op_setfield_gc emit_op_zero_ptr_field = emit_op_setfield_gc - def emit_op_getfield_gc(self, op, arglocs, regalloc, fcond): + def _genop_getfield(self, op, arglocs, regalloc, fcond): base_loc, ofs, res, size = arglocs signed = op.getdescr().is_field_signed() scale = get_scale(size.value) self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond) return fcond - emit_op_getfield_raw = emit_op_getfield_gc - emit_op_getfield_raw_pure = emit_op_getfield_gc - emit_op_getfield_gc_pure = emit_op_getfield_gc + emit_op_getfield_gc_i = _genop_getfield + emit_op_getfield_gc_r = _genop_getfield + emit_op_getfield_gc_f = _genop_getfield + emit_op_getfield_gc_pure_i = _genop_getfield + emit_op_getfield_gc_pure_r = _genop_getfield + emit_op_getfield_gc_pure_f = _genop_getfield + emit_op_getfield_raw_i = _genop_getfield + emit_op_getfield_raw_f = _genop_getfield + emit_op_getfield_raw_pure_i = _genop_getfield + emit_op_getfield_raw_pure_f = _genop_getfield def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond): base_loc, value_loc = arglocs @@ -592,7 +686,7 @@ self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond) return fcond - def emit_op_getinteriorfield_gc(self, op, arglocs, regalloc, fcond): + def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, res_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs scale = get_scale(fieldsize.value) @@ -613,6 +707,10 @@ imm(scale), signed, fcond) return fcond + emit_op_getinteriorfield_gc_i = _genop_getinteriorfield + emit_op_getinteriorfield_gc_r = _genop_getinteriorfield + emit_op_getinteriorfield_gc_f = _genop_getinteriorfield + def emit_op_setinteriorfield_gc(self, op, arglocs, regalloc, fcond): (base_loc, index_loc, value_loc, ofs_loc, ofs, itemsize, fieldsize) = arglocs @@ -697,12 +795,13 @@ self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond) return fcond - def emit_op_getarrayitem_gc(self, op, arglocs, regalloc, fcond): + def _genop_getarrayitem(self, op, arglocs, regalloc, fcond): res_loc, base_loc, ofs_loc, scale, ofs = arglocs assert ofs_loc.is_core_reg() signed = op.getdescr().is_item_signed() # scale the offset as required + # XXX we should try to encode the scale inside the "shift" part of LDR if scale.value > 0: self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value) ofs_loc = r.ip @@ -714,6 +813,17 @@ self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond) return fcond + emit_op_getarrayitem_gc_i = _genop_getarrayitem + emit_op_getarrayitem_gc_r = _genop_getarrayitem + emit_op_getarrayitem_gc_f = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_i = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_r = _genop_getarrayitem + emit_op_getarrayitem_gc_pure_f = _genop_getarrayitem + emit_op_getarrayitem_raw_i = _genop_getarrayitem + emit_op_getarrayitem_raw_f = _genop_getarrayitem + emit_op_getarrayitem_raw_pure_i = _genop_getarrayitem + emit_op_getarrayitem_raw_pure_f = _genop_getarrayitem + def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale, signed=False, fcond=c.AL): if scale.value == 3: @@ -771,10 +881,7 @@ else: assert 0 - emit_op_getarrayitem_raw = emit_op_getarrayitem_gc - emit_op_getarrayitem_gc_pure = emit_op_getarrayitem_gc - - def emit_op_raw_load(self, op, arglocs, regalloc, fcond): + def _genop_raw_load(self, op, arglocs, regalloc, fcond): res_loc, base_loc, ofs_loc, scale, ofs = arglocs assert ofs_loc.is_core_reg() # no base offset @@ -783,6 +890,9 @@ self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond) return fcond + emit_op_raw_load_i = _genop_raw_load + emit_op_raw_load_f = _genop_raw_load + def emit_op_strlen(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs if l1.is_imm(): @@ -833,7 +943,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[0], args) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[2], args) assert args[0] is not args[1] # forbidden case of aliasing - srcaddr_box = TempBox() + srcaddr_box = TempVar() forbidden_vars = [args[1], args[3], args[4], srcaddr_box] srcaddr_loc = regalloc.rm.force_allocate_reg(srcaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc, @@ -842,7 +952,7 @@ base_loc = regalloc.rm.make_sure_var_in_reg(args[1], forbidden_vars) ofs_loc = regalloc.rm.make_sure_var_in_reg(args[3], forbidden_vars) forbidden_vars = [args[4], srcaddr_box] - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, forbidden_vars) self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc, is_unicode=is_unicode) @@ -851,7 +961,7 @@ length_loc = regalloc.loc(length_box) if is_unicode: forbidden_vars = [srcaddr_box, dstaddr_box] - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, forbidden_vars) scale = self._get_unicode_item_scale() if not length_loc.is_core_reg(): @@ -952,7 +1062,7 @@ def imm(self, v): return imm(v) - def emit_op_call_assembler(self, op, arglocs, regalloc, fcond): + def _genop_call_assembler(self, op, arglocs, regalloc, fcond): if len(arglocs) == 4: [argloc, vloc, result_loc, tmploc] = arglocs else: @@ -961,6 +1071,10 @@ self._store_force_index(self._find_nearby_operation(+1)) self.call_assembler(op, argloc, vloc, result_loc, tmploc) return fcond + emit_op_call_assembler_i = _genop_call_assembler + emit_op_call_assembler_r = _genop_call_assembler + emit_op_call_assembler_f = _genop_call_assembler + emit_op_call_assembler_n = _genop_call_assembler def _call_assembler_emit_call(self, addr, argloc, resloc): ofs = self.saved_threadlocal_addr @@ -991,9 +1105,9 @@ return pos def _call_assembler_load_result(self, op, result_loc): - if op.result is not None: + if op.type != 'v': # load the return value from (tmploc, 0) - kind = op.result.type + kind = op.type descr = self.cpu.getarraydescr_for_frame(kind) if kind == FLOAT: ofs = self.cpu.unpack_arraydescr(descr) @@ -1041,15 +1155,23 @@ self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) return fcond - def emit_op_call_may_force(self, op, arglocs, regalloc, fcond): + def _genop_call_may_force(self, op, arglocs, regalloc, fcond): self._store_force_index(self._find_nearby_operation(+1)) self._emit_call(op, arglocs, fcond=fcond) return fcond + emit_op_call_may_force_i = _genop_call_may_force + emit_op_call_may_force_r = _genop_call_may_force + emit_op_call_may_force_f = _genop_call_may_force + emit_op_call_may_force_n = _genop_call_may_force - def emit_op_call_release_gil(self, op, arglocs, regalloc, fcond): + def _genop_call_release_gil(self, op, arglocs, regalloc, fcond): self._store_force_index(self._find_nearby_operation(+1)) self._emit_call(op, arglocs, is_call_release_gil=True) return fcond + emit_op_call_release_gil_i = _genop_call_release_gil + emit_op_call_release_gil_r = _genop_call_release_gil + emit_op_call_release_gil_f = _genop_call_release_gil + emit_op_call_release_gil_n = _genop_call_release_gil def _store_force_index(self, guard_op): assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or @@ -1065,7 +1187,7 @@ return regalloc.operations[regalloc.rm.position + delta] def emit_op_call_malloc_gc(self, op, arglocs, regalloc, fcond): - self.emit_op_call(op, arglocs, regalloc, fcond) + self._emit_call(op, arglocs, fcond=fcond) self.propagate_memoryerror_if_r0_is_null() self._alignment_check() return fcond @@ -1183,7 +1305,7 @@ # address that we will pass as first argument to memset(). # It can be in the same register as either one, but not in # args[2], because we're still needing the latter. - dstaddr_box = TempBox() + dstaddr_box = TempVar() dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, [args[2]]) if startindex >= 0: # a constant ofs = baseofs + startindex * itemsize @@ -1239,7 +1361,7 @@ # we need a register that is different from dstaddr_loc, # but which can be identical to length_loc (as usual, # only if the length_box is not used by future operations) - bytes_box = TempBox() + bytes_box = TempVar() bytes_loc = regalloc.rm.force_allocate_reg(bytes_box, [dstaddr_box]) self.mc.gen_load_int(r.ip.value, itemsize) diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -2,7 +2,7 @@ from rpython.rlib import rgc from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.jit.backend.llsupport.regalloc import FrameManager, \ - RegisterManager, TempBox, compute_vars_longevity, BaseRegalloc, \ + RegisterManager, TempVar, compute_vars_longevity, BaseRegalloc, \ get_scale from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm import conditions as c @@ -24,8 +24,7 @@ from rpython.jit.backend.arm.arch import WORD, JITFRAME_FIXED_SIZE from rpython.jit.codewriter import longlong from rpython.jit.metainterp.history import (Const, ConstInt, ConstFloat, - ConstPtr, BoxInt, - Box, BoxPtr, + ConstPtr, INT, REF, FLOAT) from rpython.jit.metainterp.history import TargetToken from rpython.jit.metainterp.resoperation import rop @@ -46,21 +45,21 @@ # that it is a LABEL that was not compiled yet. TargetToken._ll_loop_code = 0 -class TempInt(TempBox): +class TempInt(TempVar): type = INT def __repr__(self): return "" % (id(self),) -class TempPtr(TempBox): +class TempPtr(TempVar): type = REF def __repr__(self): return "" % (id(self),) -class TempFloat(TempBox): +class TempFloat(TempVar): type = FLOAT def __repr__(self): @@ -225,6 +224,8 @@ return self.rm.call_result_location(v) def after_call(self, v): + if v.type == 'v': + return if v.type == FLOAT: return self.vfprm.after_call(v) else: @@ -434,9 +435,11 @@ locs = self._prepare_op_int_add(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] + prepare_op_nursery_ptr_increment = prepare_op_int_add + def _prepare_op_int_sub(self, op, fcond): a0, a1 = boxes = op.getarglist() imm_a0 = check_imm_box(a0) @@ -456,7 +459,7 @@ locs = self._prepare_op_int_sub(op, fcond) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return locs + [res] def prepare_op_int_mul(self, op, fcond): @@ -468,19 +471,19 @@ self.possibly_free_vars(boxes) self.possibly_free_vars_for_op(op) - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [reg1, reg2, res] def prepare_op_int_force_ge_zero(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) - resloc = self.force_allocate_reg(op.result, [op.getarg(0)]) + resloc = self.force_allocate_reg(op, [op.getarg(0)]) return [argloc, resloc] def prepare_op_int_signext(self, op, fcond): argloc = self.make_sure_var_in_reg(op.getarg(0)) numbytes = op.getarg(1).getint() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, imm(numbytes), resloc] prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv') @@ -523,7 +526,7 @@ prepare_op_int_neg = prepare_unary_op prepare_op_int_invert = prepare_unary_op - def prepare_op_call(self, op, fcond): + def _prepare_op_call(self, op, fcond): calldescr = op.getdescr() assert calldescr is not None effectinfo = calldescr.get_extra_info() @@ -554,6 +557,11 @@ # ... return self._prepare_call(op) + prepare_op_call_i = _prepare_op_call + prepare_op_call_r = _prepare_op_call + prepare_op_call_f = _prepare_op_call + prepare_op_call_n = _prepare_op_call + def _prepare_call(self, op, force_store=[], save_all_regs=False, first_arg_index=1): args = [None] * (op.numargs() + 3) @@ -584,9 +592,7 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(force_store, save_all_regs=save_all_regs) - resloc = None - if op.result: - resloc = self.after_call(op.result) + resloc = self.after_call(op) return resloc def prepare_op_call_malloc_gc(self, op, fcond): @@ -598,12 +604,12 @@ loc1 = self.make_sure_var_in_reg(op.getarg(2)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc0, loc1, res] def _prepare_llong_to_int(self, op, fcond): loc0 = self.make_sure_var_in_reg(op.getarg(1)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc0, res] def _prepare_threadlocalref_get(self, op, fcond): @@ -611,7 +617,7 @@ calldescr = op.getdescr() size_loc = imm(calldescr.get_result_size()) sign_loc = imm(calldescr.is_result_signed()) - res_loc = self.force_allocate_reg(op.result) + res_loc = self.force_allocate_reg(op) return [ofs_loc, size_loc, sign_loc, res_loc] def _prepare_guard(self, op, args=None): @@ -669,7 +675,6 @@ l1 = self.make_sure_var_in_reg(a1, boxes) else: l1 = self.convert_to_imm(a1) - assert op.result is None arglocs = self._prepare_guard(op, [l0, l1]) self.possibly_free_vars(op.getarglist()) self.possibly_free_vars(op.getfailargs()) @@ -689,9 +694,9 @@ arg0 = ConstInt(rffi.cast(lltype.Signed, op.getarg(0).getint())) loc = self.make_sure_var_in_reg(arg0) loc1 = self.get_scratch_reg(INT, boxes) - if op.result in self.longevity: - resloc = self.force_allocate_reg(op.result, boxes) - self.possibly_free_var(op.result) + if op in self.longevity: + resloc = self.force_allocate_reg(op, boxes) + self.possibly_free_var(op) else: resloc = None pos_exc_value = imm(self.cpu.pos_exc_value()) @@ -706,55 +711,20 @@ return arglocs def prepare_op_guard_class(self, op, fcond): - return self._prepare_guard_class(op, fcond) - - prepare_op_guard_nonnull_class = prepare_op_guard_class - - def _prepare_guard_class(self, op, fcond): - assert isinstance(op.getarg(0), Box) + assert not isinstance(op.getarg(0), Const) boxes = op.getarglist() x = self.make_sure_var_in_reg(boxes[0], boxes) - y_val = rffi.cast(lltype.Signed, op.getarg(1).getint()) + y_val = rffi.cast(lltype.Signed, boxes[1].getint()) + return self._prepare_guard(op, [x, imm(y_val)]) - arglocs = [x, None, None] + prepare_op_guard_nonnull_class = prepare_op_guard_class + prepare_op_guard_gc_type = prepare_op_guard_class + prepare_op_guard_subclass = prepare_op_guard_class - offset = self.cpu.vtable_offset - if offset is not None: - y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, imm(y_val)) - - assert check_imm_arg(offset) - offset_loc = imm(offset) - - arglocs[1] = y - arglocs[2] = offset_loc - else: - # XXX hard-coded assumption: to go from an object to its class - # we use the following algorithm: - # - read the typeid from mem(locs[0]), i.e. at offset 0 - # - keep the lower 16 bits read there - # - multiply by 4 and use it as an offset in type_info_group - # - add 16 bytes, to go past the TYPE_INFO structure - classptr = y_val - # here, we have to go back from 'classptr' to the value expected - # from reading the 16 bits in the object header - from rpython.memory.gctypelayout import GCData - sizeof_ti = rffi.sizeof(GCData.TYPE_INFO) - type_info_group = llop.gc_get_type_info_group(llmemory.Address) - type_info_group = rffi.cast(lltype.Signed, type_info_group) - expected_typeid = classptr - sizeof_ti - type_info_group - expected_typeid >>= 2 - if check_imm_arg(expected_typeid): - arglocs[1] = imm(expected_typeid) - else: - y = self.get_scratch_reg(INT, forbidden_vars=boxes) - self.assembler.load(y, imm(expected_typeid)) - arglocs[1] = y - - return self._prepare_guard(op, arglocs) - - return arglocs + def prepare_op_guard_is_object(self, op, fcond): + loc_object = self.make_sure_var_in_reg(op.getarg(0)) + return self._prepare_guard(op, [loc_object]) def compute_hint_frame_locations(self, operations): # optimization only: fill in the 'hint_frame_locations' dictionary @@ -782,7 +752,7 @@ assert len(arglocs) == jump_op.numargs() for i in range(jump_op.numargs()): box = jump_op.getarg(i) - if isinstance(box, Box): + if not isinstance(box, Const): loc = arglocs[i] if loc is not None and loc.is_stack(): self.frame_manager.hint_frame_pos[box] = ( @@ -847,7 +817,7 @@ ofs = op.getarg(1).getint() return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD) - def prepare_op_getfield_gc(self, op, fcond): + def _prepare_op_getfield(self, op, fcond): a0 = op.getarg(0) ofs, size, sign = unpack_fielddescr(op.getdescr()) base_loc = self.make_sure_var_in_reg(a0) @@ -860,12 +830,19 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [base_loc, ofs_loc, res, imm(size)] - prepare_op_getfield_raw = prepare_op_getfield_gc - prepare_op_getfield_raw_pure = prepare_op_getfield_gc - prepare_op_getfield_gc_pure = prepare_op_getfield_gc + prepare_op_getfield_gc_i = _prepare_op_getfield + prepare_op_getfield_gc_r = _prepare_op_getfield + prepare_op_getfield_gc_f = _prepare_op_getfield + prepare_op_getfield_raw_i = _prepare_op_getfield + prepare_op_getfield_raw_f = _prepare_op_getfield + prepare_op_getfield_raw_pure_i = _prepare_op_getfield + prepare_op_getfield_raw_pure_f = _prepare_op_getfield + prepare_op_getfield_gc_pure_i = _prepare_op_getfield + prepare_op_getfield_gc_pure_r = _prepare_op_getfield + prepare_op_getfield_gc_pure_f = _prepare_op_getfield def prepare_op_increment_debug_counter(self, op, fcond): boxes = op.getarglist() @@ -875,7 +852,7 @@ self.free_temp_vars() return [base_loc, value_loc] - def prepare_op_getinteriorfield_gc(self, op, fcond): + def _prepare_op_getinteriorfield(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t args = op.getarglist() @@ -890,10 +867,14 @@ self.assembler.load(ofs_loc, immofs) self.possibly_free_vars_for_op(op) self.free_temp_vars() - result_loc = self.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op) return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs), imm(itemsize), imm(fieldsize)] + prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield + prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield + def prepare_op_setinteriorfield_gc(self, op, fcond): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = t @@ -920,7 +901,7 @@ base_loc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [res, base_loc, imm(ofs)] def prepare_op_setarrayitem_gc(self, op, fcond): @@ -935,7 +916,7 @@ prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc prepare_op_raw_store = prepare_op_setarrayitem_gc - def prepare_op_getarrayitem_gc(self, op, fcond): + def _prepare_op_getarrayitem(self, op, fcond): boxes = op.getarglist() size, ofs, _ = unpack_arraydescr(op.getdescr()) scale = get_scale(size) @@ -943,14 +924,22 @@ ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) assert check_imm_arg(ofs) return [res, base_loc, ofs_loc, imm(scale), imm(ofs)] - prepare_op_getarrayitem_raw = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_raw_pure = prepare_op_getarrayitem_gc - prepare_op_getarrayitem_gc_pure = prepare_op_getarrayitem_gc - prepare_op_raw_load = prepare_op_getarrayitem_gc + prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_raw_pure_f = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem + prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem + prepare_op_raw_load_i = _prepare_op_getarrayitem + prepare_op_raw_load_f = _prepare_op_getarrayitem def prepare_op_strlen(self, op, fcond): args = op.getarglist() @@ -967,8 +956,8 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.force_allocate_reg(op) + self.possibly_free_var(op) return [l0, l1, res] def prepare_op_strgetitem(self, op, fcond): @@ -984,7 +973,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, self.cpu.translate_support_code) @@ -1018,7 +1007,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [l0, l1, res] def prepare_op_unicodegetitem(self, op, fcond): @@ -1028,7 +1017,7 @@ self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, self.cpu.translate_support_code) @@ -1047,7 +1036,7 @@ return [value_loc, base_loc, ofs_loc, imm(scale), imm(basesize), imm(itemsize)] - def prepare_op_same_as(self, op, fcond): + def _prepare_op_same_as(self, op, fcond): arg = op.getarg(0) imm_arg = check_imm_box(arg) if imm_arg: @@ -1056,18 +1045,21 @@ argloc = self.make_sure_var_in_reg(arg) self.possibly_free_vars_for_op(op) self.free_temp_vars() - resloc = self.force_allocate_reg(op.result) + resloc = self.force_allocate_reg(op) return [argloc, resloc] - prepare_op_cast_ptr_to_int = prepare_op_same_as - prepare_op_cast_int_to_ptr = prepare_op_same_as + prepare_op_cast_ptr_to_int = _prepare_op_same_as + prepare_op_cast_int_to_ptr = _prepare_op_same_as + prepare_op_same_as_i = _prepare_op_same_as + prepare_op_same_as_r = _prepare_op_same_as + prepare_op_same_as_f = _prepare_op_same_as def prepare_op_call_malloc_nursery(self, op, fcond): size_box = op.getarg(0) assert isinstance(size_box, ConstInt) size = size_box.getint() - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1085,13 +1077,13 @@ def prepare_op_call_malloc_nursery_varsize_frame(self, op, fcond): size_box = op.getarg(0) - assert isinstance(size_box, BoxInt) # we cannot have a const here! + assert not isinstance(size_box, ConstInt) # we cannot have a const here! # sizeloc must be in a register, but we can free it now # (we take care explicitly of conflicts with r0 or r1) sizeloc = self.rm.make_sure_var_in_reg(size_box) self.rm.possibly_free_var(size_box) # - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # t = TempInt() self.rm.force_allocate_reg(t, selected_reg=r.r1) @@ -1115,11 +1107,11 @@ # for boehm, this function should never be called arraydescr = op.getdescr() length_box = op.getarg(2) - assert isinstance(length_box, BoxInt) # we cannot have a const here! + assert not isinstance(length_box, Const) # we cannot have a const here! # the result will be in r0 - self.rm.force_allocate_reg(op.result, selected_reg=r.r0) + self.rm.force_allocate_reg(op, selected_reg=r.r0) # we need r1 as a temporary - tmp_box = TempBox() + tmp_box = TempVar() self.rm.force_allocate_reg(tmp_box, selected_reg=r.r1) gcmap = self.get_gcmap([r.r0, r.r1]) # allocate the gcmap *before* self.rm.possibly_free_var(tmp_box) @@ -1144,7 +1136,6 @@ prepare_op_leave_portal_frame = void def prepare_op_cond_call_gc_wb(self, op, fcond): - assert op.result is None # we force all arguments in a reg because it will be needed anyway by # the following setfield_gc or setarrayitem_gc. It avoids loading it # twice from the memory. @@ -1160,7 +1151,6 @@ prepare_op_cond_call_gc_wb_array = prepare_op_cond_call_gc_wb def prepare_op_cond_call(self, op, fcond): - assert op.result is None assert 2 <= op.numargs() <= 4 + 2 tmpreg = self.get_scratch_reg(INT, selected_reg=r.r4) v = op.getarg(1) @@ -1178,8 +1168,7 @@ def prepare_op_force_token(self, op, fcond): # XXX for now we return a regular reg - res_loc = self.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res_loc = self.force_allocate_reg(op) return [res_loc] def prepare_op_label(self, op, fcond): @@ -1194,14 +1183,14 @@ # of some guard position = self.rm.position for arg in inputargs: - assert isinstance(arg, Box) + assert not isinstance(arg, Const) if self.last_real_usage.get(arg, -1) <= position: self.force_spill_var(arg) # for i in range(len(inputargs)): arg = inputargs[i] - assert isinstance(arg, Box) + assert not isinstance(arg, Const) loc = self.loc(arg) arglocs[i] = loc if loc.is_core_reg() or loc.is_vfp_reg(): @@ -1228,18 +1217,33 @@ self.assembler.store_force_descr(op, fail_locs[1:], fail_locs[0].value) self.possibly_free_vars(op.getfailargs()) - def prepare_op_call_may_force(self, op, fcond): + def _prepare_op_call_may_force(self, op, fcond): return self._prepare_call(op, save_all_regs=True) - def prepare_op_call_release_gil(self, op, fcond): + prepare_op_call_may_force_i = _prepare_op_call_may_force + prepare_op_call_may_force_r = _prepare_op_call_may_force + prepare_op_call_may_force_f = _prepare_op_call_may_force + prepare_op_call_may_force_n = _prepare_op_call_may_force + + def _prepare_op_call_release_gil(self, op, fcond): return self._prepare_call(op, save_all_regs=True, first_arg_index=2) - def prepare_op_call_assembler(self, op, fcond): + prepare_op_call_release_gil_i = _prepare_op_call_release_gil + prepare_op_call_release_gil_r = _prepare_op_call_release_gil + prepare_op_call_release_gil_f = _prepare_op_call_release_gil + prepare_op_call_release_gil_n = _prepare_op_call_release_gil + + def _prepare_op_call_assembler(self, op, fcond): locs = self.locs_for_call_assembler(op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) resloc = self._call(op, locs + [tmploc], save_all_regs=True) return locs + [resloc, tmploc] + prepare_op_call_assembler_i = _prepare_op_call_assembler + prepare_op_call_assembler_r = _prepare_op_call_assembler + prepare_op_call_assembler_f = _prepare_op_call_assembler + prepare_op_call_assembler_n = _prepare_op_call_assembler + def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr args = gc_ll_descr.args_for_new(new_args) @@ -1269,18 +1273,17 @@ loc = self.make_sure_var_in_reg(op.getarg(1)) self.possibly_free_vars_for_op(op) self.free_temp_vars() - res = self.vfprm.force_allocate_reg(op.result) - self.possibly_free_var(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc, res] def prepare_op_cast_float_to_int(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.rm.force_allocate_reg(op.result) + res = self.rm.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_int_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.vfprm.force_allocate_reg(op.result) + res = self.vfprm.force_allocate_reg(op) return [loc1, res] def prepare_force_spill(self, op, fcond): @@ -1292,17 +1295,17 @@ #def prepare_op_read_timestamp(self, op, fcond): # loc = self.get_scratch_reg(INT) - # res = self.vfprm.force_allocate_reg(op.result) + # res = self.vfprm.force_allocate_reg(op) # return [loc, res] def prepare_op_cast_float_to_singlefloat(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] def prepare_op_cast_singlefloat_to_float(self, op, fcond): loc1 = self.make_sure_var_in_reg(op.getarg(0)) - res = self.force_allocate_reg(op.result) + res = self.force_allocate_reg(op) return [loc1, res] diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -2,9 +2,9 @@ from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.backend.test.runner_test import LLtypeBackendTest,\ boxfloat, constfloat -from rpython.jit.metainterp.history import (BasicFailDescr, BasicFinalDescr, - BoxInt) -from rpython.jit.metainterp.resoperation import ResOperation, rop +from rpython.jit.metainterp.history import BasicFailDescr, BasicFinalDescr +from rpython.jit.metainterp.resoperation import (ResOperation, rop, + InputArgInt) from rpython.jit.tool.oparser import parse from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper import rclass @@ -52,30 +52,29 @@ def test_result_is_spilled(self): cpu = self.cpu - inp = [BoxInt(i) for i in range(1, 15)] - out = [BoxInt(i) for i in range(1, 15)] + inp = [InputArgInt(i) for i in range(1, 15)] looptoken = JitCellToken() targettoken = TargetToken() operations = [ - ResOperation(rop.LABEL, inp, None, descr=targettoken), - ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[0]), - ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[1]), - ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[2]), - ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[3]), - ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[4]), - ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[5]), - ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[6]), - ResOperation(rop.INT_ADD, [inp[0], inp[1]], out[7]), - ResOperation(rop.INT_ADD, [inp[2], inp[3]], out[8]), - ResOperation(rop.INT_ADD, [inp[4], inp[5]], out[9]), - ResOperation(rop.INT_ADD, [inp[6], inp[7]], out[10]), - ResOperation(rop.INT_ADD, [inp[8], inp[9]], out[11]), - ResOperation(rop.INT_ADD, [inp[10], inp[11]], out[12]), - ResOperation(rop.INT_ADD, [inp[12], inp[13]], out[13]), - ResOperation(rop.GUARD_FALSE, [inp[1]], None, descr=BasicFailDescr(1)), - ResOperation(rop.FINISH, [inp[1]], None, descr=BasicFinalDescr(1)), + ResOperation(rop.LABEL, inp, descr=targettoken), + ResOperation(rop.INT_ADD, [inp[0], inp[1]]), + ResOperation(rop.INT_ADD, [inp[2], inp[3]]), + ResOperation(rop.INT_ADD, [inp[4], inp[5]]), + ResOperation(rop.INT_ADD, [inp[6], inp[7]]), + ResOperation(rop.INT_ADD, [inp[8], inp[9]]), + ResOperation(rop.INT_ADD, [inp[10], inp[11]]), + ResOperation(rop.INT_ADD, [inp[12], inp[13]]), + ResOperation(rop.INT_ADD, [inp[0], inp[1]]), + ResOperation(rop.INT_ADD, [inp[2], inp[3]]), + ResOperation(rop.INT_ADD, [inp[4], inp[5]]), + ResOperation(rop.INT_ADD, [inp[6], inp[7]]), + ResOperation(rop.INT_ADD, [inp[8], inp[9]]), + ResOperation(rop.INT_ADD, [inp[10], inp[11]]), + ResOperation(rop.INT_ADD, [inp[12], inp[13]]), + ResOperation(rop.GUARD_FALSE, [inp[1]], descr=BasicFailDescr(1)), + ResOperation(rop.FINISH, [inp[1]], descr=BasicFinalDescr(1)), ] - operations[-2].setfailargs(out) + operations[-2].setfailargs(operations[1:15]) cpu.compile_loop(inp, operations, looptoken) args = [i for i in range(1, 15)] deadframe = self.cpu.execute_token(looptoken, *args) @@ -104,7 +103,7 @@ lt2.outermost_jitdriver_sd = FakeJitDriverSD() loop1 = parse(''' [i0] - i1 = call_assembler(i0, descr=lt2) + i1 = call_assembler_i(i0, descr=lt2) guard_not_forced()[] finish(i1) ''', namespace=locals()) @@ -181,19 +180,19 @@ def test_float_field(self): if not self.cpu.supports_floats: py.test.skip('requires floats') + t_box, T_box, _ = self.alloc_instance(self.TFloat) floatdescr = self.cpu.fielddescrof(self.SFloat, 'float') - t_box, T_box = self.alloc_instance(self.TFloat) self.execute_operation(rop.SETFIELD_GC, [t_box, boxfloat(3.4)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == 3.4 + assert longlong.getrealfloat(res) == 3.4 # self.execute_operation(rop.SETFIELD_GC, [t_box, constfloat(-3.6)], 'void', descr=floatdescr) - res = self.execute_operation(rop.GETFIELD_GC, [t_box], + res = self.execute_operation(rop.GETFIELD_GC_F, [t_box], 'float', descr=floatdescr) - assert res.getfloat() == -3.6 + assert longlong.getrealfloat(res) == -3.6 def test_compile_loop_many_int_args(self): for numargs in range(2, 30): @@ -269,13 +268,13 @@ targettoken = TargetToken() ops = """ [i0, f3] - i2 = same_as(i0) # but forced to be in a register + i2 = same_as_i(i0) # but forced to be in a register force_spill(i2) force_spill(f3) f4 = float_add(f3, 5.0) label(f3, f4, descr=targettoken) force_spill(f3) - f5 = same_as(f3) # but forced to be in a register + f5 = same_as_f(f3) # but forced to be in a register finish(f5) """ faildescr = BasicFailDescr(2) @@ -284,8 +283,8 @@ info = self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) ops2 = """ [i0, f1] - i1 = same_as(i0) - f2 = same_as(f1) + i1 = same_as_i(i0) + f2 = same_as_f(f1) f3 = float_add(f1, 10.0) force_spill(f3) force_spill(i1) diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -122,11 +122,15 @@ def getcpufeatures(backend_name="auto"): - """NOT_RPYTHON""" - cpucls = getcpuclass(backend_name) - return [attr[len('supports_'):] for attr in dir(cpucls) - if attr.startswith('supports_') - and getattr(cpucls, attr)] + if backend_name == "auto": + backend_name = autodetect() + return { + MODEL_X86: ['floats', 'singlefloats', 'longlong'], + MODEL_X86_NO_SSE2: ['longlong'], + MODEL_X86_64: ['floats', 'singlefloats'], + MODEL_ARM: ['floats', 'singlefloats', 'longlong'], + MODEL_PPC_64: [], # we don't even have PPC directory, so no + }[backend_name] if __name__ == '__main__': if len(sys.argv) > 1: 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 @@ -16,6 +16,7 @@ from rpython.rlib.clibffi import FFI_DEFAULT_ABI from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_ulonglong +from rpython.rlib.objectmodel import Symbolic class LLTrace(object): has_been_freed = False @@ -25,7 +26,9 @@ # We need to clone the list of operations because the # front-end will mutate them under our feet again. We also # need to make sure things get freed. - def mapping(box, _cache={}): + _cache={} + + def mapping(box): if isinstance(box, Const) or box is None: return box try: @@ -46,8 +49,8 @@ newdescr = None newop = op.copy_and_change(op.getopnum(), map(mapping, op.getarglist()), - mapping(op.result), newdescr) + _cache[op] = newop if op.getfailargs() is not None: newop.setfailargs(map(mapping, op.getfailargs())) self.operations.append(newop) @@ -86,15 +89,45 @@ def get_result_type(self): return getkind(self.RESULT)[0] + get_normalized_result_type = get_result_type + +class TypeIDSymbolic(Symbolic): + def __init__(self, STRUCT_OR_ARRAY): + self.STRUCT_OR_ARRAY = STRUCT_OR_ARRAY + + def __eq__(self, other): + return self.STRUCT_OR_ARRAY is other.STRUCT_OR_ARRAY + + def __ne__(self, other): + return not self == other + class SizeDescr(AbstractDescr): - def __init__(self, S): + def __init__(self, S, vtable, runner): + assert not isinstance(vtable, bool) self.S = S + self._vtable = vtable + self._is_object = bool(vtable) + self._runner = runner - def as_vtable_size_descr(self): - return self + def get_all_fielddescrs(self): + return self.all_fielddescrs - def count_fields_if_immutable(self): - return heaptracker.count_fields_if_immutable(self.S) + def is_object(self): + return self._is_object + + def get_vtable(self): + assert self._vtable is not None + if self._vtable is Ellipsis: + self._vtable = heaptracker.get_vtable_for_gcstruct(self._runner, + self.S) + return heaptracker.adr2int(llmemory.cast_ptr_to_adr(self._vtable)) + + def is_immutable(self): + return heaptracker.is_immutable_struct(self.S) + + def get_type_id(self): + assert isinstance(self.S, lltype.GcStruct) + return TypeIDSymbolic(self.S) # integer-like symbolic def __repr__(self): return 'SizeDescr(%r)' % (self.S,) @@ -104,10 +137,21 @@ self.S = S self.fieldname = fieldname self.FIELD = getattr(S, fieldname) + self.index = heaptracker.get_fielddescr_index_in(S, fieldname) + self._is_pure = S._immutable_field(fieldname) + + def is_always_pure(self): + return self._is_pure + + def get_parent_descr(self): + return self.parent_descr def get_vinfo(self): return self.vinfo + def get_index(self): + return self.index + def __repr__(self): return 'FieldDescr(%r, %r)' % (self.S, self.fieldname) @@ -146,11 +190,20 @@ rffi.cast(TYPE, -1) == -1) class ArrayDescr(AbstractDescr): - def __init__(self, A): + all_interiorfielddescrs = None + + def __init__(self, A, runner): self.A = self.OUTERA = A + self._is_pure = A._immutable_field(None) if isinstance(A, lltype.Struct): self.A = A._flds[A._arrayfld] + def is_always_pure(self): + return self._is_pure + + def get_all_fielddescrs(self): + return self.all_interiorfielddescrs + def __repr__(self): return 'ArrayDescr(%r)' % (self.OUTERA,) @@ -184,12 +237,27 @@ return intbounds.get_integer_max( not _is_signed_kind(self.A.OF), rffi.sizeof(self.A.OF)) + def get_type_id(self): + assert isinstance(self.A, lltype.GcArray) + return TypeIDSymbolic(self.A) # integer-like symbolic + class InteriorFieldDescr(AbstractDescr): - def __init__(self, A, fieldname): + def __init__(self, A, fieldname, runner): self.A = A self.fieldname = fieldname self.FIELD = getattr(A.OF, fieldname) + self.arraydescr = runner.arraydescrof(A) + self.fielddescr = runner.fielddescrof(A.OF, fieldname) + + def get_index(self): + return self.fielddescr.get_index() + + def get_arraydescr(self): + return self.arraydescr + + def get_field_descr(self): + return self.fielddescr def __repr__(self): return 'InteriorFieldDescr(%r, %r)' % (self.A, self.fieldname) @@ -232,6 +300,7 @@ supports_floats = True supports_longlong = r_uint is not r_ulonglong supports_singlefloats = True + supports_guard_gc_type = True translate_support_code = False is_llgraph = True @@ -336,10 +405,10 @@ values = [] for box in frame.force_guard_op.getfailargs(): if box is not None: - if box is not frame.current_op.result: + if box is not frame.current_op: value = frame.env[box] else: - value = box.value # 0 or 0.0 or NULL + value = box.getvalue() # 0 or 0.0 or NULL else: value = None values.append(value) @@ -367,14 +436,19 @@ self.descrs[key] = descr return descr - def sizeof(self, S): + def sizeof(self, S, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): key = ('size', S) try: - return self.descrs[key] + descr = self.descrs[key] except KeyError: - descr = SizeDescr(S) + descr = SizeDescr(S, vtable, self) self.descrs[key] = descr - return descr + descr.all_fielddescrs = heaptracker.all_fielddescrs(self, S, + get_field_descr=LLGraphCPU.fielddescrof) + if descr._is_object and vtable is not Ellipsis: + assert vtable + heaptracker.testing_gcstruct2vtable.setdefault(S, vtable) + return descr def fielddescrof(self, S, fieldname): key = ('field', S, fieldname) @@ -383,6 +457,12 @@ except KeyError: descr = FieldDescr(S, fieldname) self.descrs[key] = descr + if (isinstance(S, lltype.GcStruct) and + heaptracker.has_gcstruct_a_vtable(S)): + vtable = Ellipsis + else: + vtable = None + descr.parent_descr = self.sizeof(S, vtable) if self.vinfo_for_tests is not None: descr.vinfo = self.vinfo_for_tests return descr @@ -392,8 +472,12 @@ try: return self.descrs[key] except KeyError: - descr = ArrayDescr(A) + descr = ArrayDescr(A, self) self.descrs[key] = descr + if isinstance(A, lltype.Array) and isinstance(A.OF, lltype.Struct): + descrs = heaptracker.all_interiorfielddescrs(self, + A, get_field_descr=LLGraphCPU.interiorfielddescrof) + descr.all_interiorfielddescrs = descrs return descr def interiorfielddescrof(self, A, fieldname): @@ -401,7 +485,7 @@ try: return self.descrs[key] except KeyError: - descr = InteriorFieldDescr(A, fieldname) + descr = InteriorFieldDescr(A, fieldname, self) self.descrs[key] = descr return descr @@ -435,6 +519,22 @@ self.descrs[key] = descr return descr + def check_is_object(self, gcptr): + """Check if the given, non-null gcptr refers to an rclass.OBJECT + or not at all (an unrelated GcStruct or a GcArray). Only usable + in the llgraph backend, or after translation of a real backend.""" + ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr()) + T = lltype.typeOf(ptr).TO + return heaptracker.has_gcstruct_a_vtable(T) or T is rclass.OBJECT + + def get_actual_typeid(self, gcptr): + """Fetch the actual typeid of the given gcptr, as an integer. + Only usable in the llgraph backend, or after translation of a + real backend. (Here in the llgraph backend, returns a + TypeIDSymbolic instead of a real integer.)""" + ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr()) + return TypeIDSymbolic(lltype.typeOf(ptr).TO) + # ------------------------------------------------------------ def maybe_on_top_of_llinterp(self, func, args, RESULT): @@ -461,13 +561,17 @@ p = support.cast_arg(lltype.Ptr(descr.S), p) return support.cast_result(descr.FIELD, getattr(p, descr.fieldname)) - bh_getfield_gc_pure = bh_getfield_gc + bh_getfield_gc_pure_i = bh_getfield_gc + bh_getfield_gc_pure_r = bh_getfield_gc + bh_getfield_gc_pure_f = bh_getfield_gc bh_getfield_gc_i = bh_getfield_gc bh_getfield_gc_r = bh_getfield_gc bh_getfield_gc_f = bh_getfield_gc bh_getfield_raw = bh_getfield_gc - bh_getfield_raw_pure = bh_getfield_raw + bh_getfield_raw_pure_i = bh_getfield_raw + bh_getfield_raw_pure_r = bh_getfield_raw + bh_getfield_raw_pure_f = bh_getfield_raw bh_getfield_raw_i = bh_getfield_raw bh_getfield_raw_r = bh_getfield_raw bh_getfield_raw_f = bh_getfield_raw @@ -495,13 +599,17 @@ array = a._obj return support.cast_result(descr.A.OF, array.getitem(index)) - bh_getarrayitem_gc_pure = bh_getarrayitem_gc + bh_getarrayitem_gc_pure_i = bh_getarrayitem_gc + bh_getarrayitem_gc_pure_r = bh_getarrayitem_gc + bh_getarrayitem_gc_pure_f = bh_getarrayitem_gc bh_getarrayitem_gc_i = bh_getarrayitem_gc bh_getarrayitem_gc_r = bh_getarrayitem_gc bh_getarrayitem_gc_f = bh_getarrayitem_gc bh_getarrayitem_raw = bh_getarrayitem_gc - bh_getarrayitem_raw_pure = bh_getarrayitem_raw + bh_getarrayitem_raw_pure_i = bh_getarrayitem_raw + bh_getarrayitem_raw_pure_r = bh_getarrayitem_raw + bh_getarrayitem_raw_pure_f = bh_getarrayitem_raw bh_getarrayitem_raw_i = bh_getarrayitem_raw bh_getarrayitem_raw_r = bh_getarrayitem_raw bh_getarrayitem_raw_f = bh_getarrayitem_raw @@ -634,11 +742,11 @@ return lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(sizedescr.S, zero=True)) - def bh_new_with_vtable(self, vtable, descr): + def bh_new_with_vtable(self, descr): result = lltype.malloc(descr.S, zero=True) result_as_objptr = lltype.cast_pointer(rclass.OBJECTPTR, result) result_as_objptr.typeptr = support.cast_from_int(rclass.CLASSTYPE, - vtable) + descr.get_vtable()) return lltype.cast_opaque_ptr(llmemory.GCREF, result) def bh_new_array(self, length, arraydescr): @@ -749,8 +857,8 @@ i = 0 self.do_renaming(targetargs, j.args) continue - if op.result is not None: - self.setenv(op.result, resval) + if op.type != 'v': + self.setenv(op, resval) else: assert resval is None i += 1 @@ -823,6 +931,32 @@ self.execute_guard_nonnull(descr, arg) self.execute_guard_class(descr, arg, klass) + def execute_guard_gc_type(self, descr, arg, typeid): + assert isinstance(typeid, TypeIDSymbolic) + TYPE = arg._obj.container._TYPE + if TYPE != typeid.STRUCT_OR_ARRAY: + self.fail_guard(descr) + + def execute_guard_is_object(self, descr, arg): + TYPE = arg._obj.container._TYPE + while TYPE is not rclass.OBJECT: + if not isinstance(TYPE, lltype.GcStruct): # or TYPE is None + self.fail_guard(descr) + return + _, TYPE = TYPE._first_struct() + + def execute_guard_subclass(self, descr, arg, klass): + value = lltype.cast_opaque_ptr(rclass.OBJECTPTR, arg) + expected_class = llmemory.cast_adr_to_ptr( + llmemory.cast_int_to_adr(klass), + rclass.CLASSTYPE) + if (expected_class.subclassrange_min + <= value.typeptr.subclassrange_min + <= expected_class.subclassrange_max): + pass + else: + self.fail_guard(descr) + def execute_guard_no_exception(self, descr): if self.last_exception is not None: self.fail_guard(descr) @@ -894,6 +1028,7 @@ def execute_guard_overflow(self, descr): if not self.overflow_flag: self.fail_guard(descr) + return lltype.nullptr(llmemory.GCREF.TO) # I think it's fine.... def execute_jump(self, descr, *args): raise Jump(descr._llgraph_target, args) @@ -908,9 +1043,9 @@ if not cond: return # cond_call can't have a return value - self.execute_call(calldescr, func, *args) + self.execute_call_n(calldescr, func, *args) - def execute_call(self, calldescr, func, *args): + def _execute_call(self, calldescr, func, *args): effectinfo = calldescr.get_extra_info() if effectinfo is not None and hasattr(effectinfo, 'oopspecindex'): oopspecindex = effectinfo.oopspecindex @@ -926,16 +1061,25 @@ res = _example_res[getkind(TP.RESULT)[0]] return res - def execute_call_may_force(self, calldescr, func, *args): - call_op = self.lltrace.operations[self.current_index] + execute_call_i = _execute_call + execute_call_r = _execute_call + execute_call_f = _execute_call + execute_call_n = _execute_call + + def _execute_call_may_force(self, calldescr, func, *args): guard_op = self.lltrace.operations[self.current_index + 1] assert guard_op.getopnum() == rop.GUARD_NOT_FORCED self.force_guard_op = guard_op - res = self.execute_call(calldescr, func, *args) + res = self._execute_call(calldescr, func, *args) del self.force_guard_op return res - def execute_call_release_gil(self, descr, saveerr, func, *args): + execute_call_may_force_n = _execute_call_may_force + execute_call_may_force_r = _execute_call_may_force + execute_call_may_force_f = _execute_call_may_force + execute_call_may_force_i = _execute_call_may_force + + def _execute_call_release_gil(self, descr, saveerr, func, *args): if hasattr(descr, '_original_func_'): func = descr._original_func_ # see pyjitpl.py # we want to call the function that does the aroundstate @@ -960,61 +1104,74 @@ del self.force_guard_op return support.cast_result(descr.RESULT, result) - def execute_call_assembler(self, descr, *args): - # XXX simplify the following a bit - # - # pframe = CALL_ASSEMBLER(args..., descr=looptoken) - # ==> - # pframe = CALL looptoken.loopaddr(*args) - # JUMP_IF_FAST_PATH @fastpath - # res = CALL assembler_call_helper(pframe) - # jmp @done - # @fastpath: - # res = GETFIELD(pframe, 'result') - # @done: - # - call_op = self.lltrace.operations[self.current_index] - guard_op = self.lltrace.operations[self.current_index + 1] - assert guard_op.getopnum() == rop.GUARD_NOT_FORCED - self.force_guard_op = guard_op - pframe = self.cpu._execute_token(descr, *args) - del self.force_guard_op - # - jd = descr.outermost_jitdriver_sd - assert jd is not None, ("call_assembler(): the loop_token needs " - "to have 'outermost_jitdriver_sd'") - if jd.index_of_virtualizable != -1: - vable = args[jd.index_of_virtualizable] - else: - vable = lltype.nullptr(llmemory.GCREF.TO) - # - # Emulate the fast path - # - faildescr = self.cpu.get_latest_descr(pframe) - if faildescr == self.cpu.done_with_this_frame_descr_int: - return self.cpu.get_int_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_ref: - return self.cpu.get_ref_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_float: - return self.cpu.get_float_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_void: - return None + execute_call_release_gil_n = _execute_call_release_gil + execute_call_release_gil_i = _execute_call_release_gil + execute_call_release_gil_r = _execute_call_release_gil + execute_call_release_gil_f = _execute_call_release_gil - assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish - try: - result = assembler_helper_ptr(pframe, vable) - except LLException, lle: - assert self.last_exception is None, "exception left behind" - self.last_exception = lle - # fish op - op = self.current_op - return op.result and op.result.value - if isinstance(result, float): - result = support.cast_to_floatstorage(result) - return result + def _new_execute_call_assembler(def_val): + def _execute_call_assembler(self, descr, *args): + # XXX simplify the following a bit + # + # pframe = CALL_ASSEMBLER(args..., descr=looptoken) + # ==> + # pframe = CALL looptoken.loopaddr(*args) + # JUMP_IF_FAST_PATH @fastpath + # res = CALL assembler_call_helper(pframe) + # jmp @done + # @fastpath: + # res = GETFIELD(pframe, 'result') + # @done: + # + call_op = self.lltrace.operations[self.current_index] + guard_op = self.lltrace.operations[self.current_index + 1] + assert guard_op.getopnum() == rop.GUARD_NOT_FORCED + self.force_guard_op = guard_op + pframe = self.cpu._execute_token(descr, *args) + del self.force_guard_op + # + jd = descr.outermost_jitdriver_sd + assert jd is not None, ("call_assembler(): the loop_token needs " + "to have 'outermost_jitdriver_sd'") + if jd.index_of_virtualizable != -1: + vable = args[jd.index_of_virtualizable] + else: + vable = lltype.nullptr(llmemory.GCREF.TO) + # + # Emulate the fast path + # + faildescr = self.cpu.get_latest_descr(pframe) + if faildescr == self.cpu.done_with_this_frame_descr_int: + return self.cpu.get_int_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_ref: + return self.cpu.get_ref_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_float: + return self.cpu.get_float_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_void: + return None - def execute_same_as(self, _, x): + assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish + try: + result = assembler_helper_ptr(pframe, vable) + except LLException, lle: + assert self.last_exception is None, "exception left behind" + self.last_exception = lle + # fish op + result = def_val + if isinstance(result, float): + result = support.cast_to_floatstorage(result) + return result + return _execute_call_assembler + + execute_call_assembler_i = _new_execute_call_assembler(0) + execute_call_assembler_r = _new_execute_call_assembler(lltype.nullptr(llmemory.GCREF.TO)) + execute_call_assembler_f = _new_execute_call_assembler(0.0) + execute_call_assembler_n = _new_execute_call_assembler(None) + + def execute_same_as_i(self, _, x): return x + execute_same_as_f = execute_same_as_i + execute_same_as_r = execute_same_as_i def execute_debug_merge_point(self, descr, *args): from rpython.jit.metainterp.warmspot import get_stats @@ -1031,9 +1188,8 @@ def execute_leave_portal_frame(self, descr, *args): pass - def execute_new_with_vtable(self, _, vtable): - descr = heaptracker.vtable2descr(self.cpu, vtable) - return self.cpu.bh_new_with_vtable(vtable, descr) + def execute_new_with_vtable(self, descr): + return self.cpu.bh_new_with_vtable(descr) def execute_force_token(self, _): return self diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -3,7 +3,7 @@ from rpython.jit.backend.llsupport.symbolic import WORD from rpython.jit.backend.llsupport.codemap import CodemapBuilder from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken, - ConstInt, BoxInt, AbstractFailDescr) + ConstInt, AbstractFailDescr) from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.rlib import rgc from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints_for, @@ -223,11 +223,11 @@ self._call_assembler_emit_call(self.imm(descr._ll_function_addr), From noreply at buildbot.pypy.org Tue Sep 8 15:11:55 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 15:11:55 +0200 (CEST) Subject: [pypy-commit] pypy optresult-unroll: close to be merged branch Message-ID: <20150908131155.40C241C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult-unroll Changeset: r79544:26faff042c47 Date: 2015-09-08 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/26faff042c47/ Log: close to be merged branch From noreply at buildbot.pypy.org Tue Sep 8 15:11:57 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 15:11:57 +0200 (CEST) Subject: [pypy-commit] pypy default: empty merge Message-ID: <20150908131157.48CE51C03B3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79545:7597949708cf Date: 2015-09-08 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/7597949708cf/ Log: empty merge From noreply at buildbot.pypy.org Tue Sep 8 17:15:44 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 17:15:44 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit fixes Message-ID: <20150908151544.B70EC1C1215@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79546:f3a481ec3c35 Date: 2015-09-08 17:15 +0200 http://bitbucket.org/pypy/pypy/changeset/f3a481ec3c35/ Log: 32-bit fixes diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -622,12 +622,12 @@ elif isinstance(value, bool): assert op.type == 'i' op.setint(int(value)) - elif isinstance(value, float): - assert op.type == 'f' - op.setfloatstorage(value) elif lltype.typeOf(value) == lltype.Signed: assert op.type == 'i' op.setint(value) + elif lltype.typeOf(value) is longlong.FLOATSTORAGE: + assert op.type == 'f' + op.setfloatstorage(value) else: assert lltype.typeOf(value) == llmemory.GCREF assert op.type == 'r' diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -131,7 +131,7 @@ return 'ConstPtr(ptr' + str(mv) + ')' return 'ConstPtr(null)' elif isinstance(arg, ConstFloat): - return str(arg.getfloatstorage()) + return str(arg.getfloat()) elif arg is None: return 'None' elif arg.type == 'i': 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 @@ -2,7 +2,7 @@ import py -from rpython.jit.codewriter import heaptracker +from rpython.jit.codewriter import heaptracker, longlong from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr from rpython.jit.metainterp import history, compile, resume, executor, jitexc @@ -3013,7 +3013,7 @@ rop.GETARRAYITEM_RAW_F, [box_exchange_buffer, ConstInt(ofs // itemsize)], - 0.0, descr) + longlong.ZEROF, descr) else: assert kind == 'v' continue diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -409,7 +409,7 @@ type = 'f' - _resfloat = 0.0 + _resfloat = longlong.ZEROF def getfloatstorage(self): return self._resfloat From noreply at buildbot.pypy.org Tue Sep 8 17:28:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 8 Sep 2015 17:28:43 +0200 (CEST) Subject: [pypy-commit] pypy default: More 32-bit fixes Message-ID: <20150908152843.7936F1C1215@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79547:38f26fb5de09 Date: 2015-09-08 17:26 +0200 http://bitbucket.org/pypy/pypy/changeset/38f26fb5de09/ Log: More 32-bit fixes diff --git a/rpython/jit/backend/test/calling_convention_test.py b/rpython/jit/backend/test/calling_convention_test.py --- a/rpython/jit/backend/test/calling_convention_test.py +++ b/rpython/jit/backend/test/calling_convention_test.py @@ -373,6 +373,7 @@ [funcbox] + argslist, 'float', descr=calldescr) expected = func(*argvalues) + res = longlong.getrealfloat(res) assert abs(res - expected) < 0.0001 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -680,7 +680,7 @@ args = [op.getarg(1), op.getarg(2)] loc1 = self.load_xmm_aligned_16_bytes(args[0]) loc2 = self.load_xmm_aligned_16_bytes(args[1], args) - tmpxvar = TempBox() + tmpxvar = TempVar() loc3 = self.xrm.force_allocate_reg(tmpxvar, args) self.xrm.possibly_free_var(tmpxvar) loc0 = self.rm.force_allocate_reg(op, need_lower_byte=True) @@ -691,11 +691,11 @@ box = op.getarg(2) if not isinstance(box, ConstFloat): return False - if box.getlonglong() != 0: + if box.getfloat() != 0.0: # NaNs are also != 0.0 return False - # "x < 0" + # "x < 0.0" or maybe "x < -0.0" which is the same box = op.getarg(1) - assert isinstance(box, BoxFloat) + assert box.type == FLOAT loc1 = self.xrm.make_sure_var_in_reg(box) loc0 = self.rm.force_allocate_reg(op) self.perform_llong(op, [loc1], loc0) @@ -720,7 +720,7 @@ loc2 = None # unused else: loc1 = self.rm.make_sure_var_in_reg(box) - tmpxvar = TempBox() + tmpxvar = TempVar() loc2 = self.xrm.force_allocate_reg(tmpxvar, [op]) self.xrm.possibly_free_var(tmpxvar) self.perform_llong(op, [loc1, loc2], loc0) diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -83,10 +83,6 @@ def getfloat(self): return longlong.getrealfloat(self.getfloatstorage()) - def getlonglong(self): - assert longlong.supports_longlong - return self.getfloatstorage() - def getref_base(self): raise NotImplementedError From noreply at buildbot.pypy.org Tue Sep 8 17:37:05 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 17:37:05 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: draft a blog post Message-ID: <20150908153705.CA1281C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5547:a979df8a839e Date: 2015-09-08 17:37 +0200 http://bitbucket.org/pypy/extradoc/changeset/a979df8a839e/ Log: draft a blog post diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst new file mode 100644 --- /dev/null +++ b/blog/draft/warmup-improvements.rst @@ -0,0 +1,51 @@ +Hello everyone! + +I'm very pleased to announce that we've just managed to merge optresult branch. +Under this cryptic name is the biggest JIT refactoring we've done in a couple +years, mostly focused on the warmup time and memory impact of PyPy. + +To understand why we did that, let's look back in time - back when we +got the first working JIT prototype in 2009 we were focused exclusively +on the peak performance with some consideration towards memory usage, but +without serious consideration towards warmup time. This means we accumulated +quite a bit of technical debt over time that we're trying, with difficulty, +to address right now. + +The branch does "one" thing - it changes the underlaying model of how operations +are represented during the tracing and optimizations. Let's consider a simple +loop like that:: + + [i0, i1] + i2 = int_add(i0, i1) + i3 = int_add(i2, 1) + i4 = int_is_true(i3) + guard_true(i4) + jump(i3, i2) + +The original representation would allocate a ``Box`` for each of ``i0`` - ``i4`` +and then store those boxes in instances of ``ResOperation``. The list of such +operations would then go to the optimizer. Those lists are big - we usually +remove ``90%`` of them during optimizations, but they can be couple thousand +elements. Overall allocating those big lists takes a toll on warmup time, +especially due to the GC pressure. The branch removes the existance of ``Box`` +completely, instead using link to ``ResOperation`` itself. So say in the above +example, ``i2`` would refer to its producer - ``i2 = int_add(i0, i1)`` with +arguments getting special treatment. + +That alone reduces the GC pressure slightly, but we went an extra mile +to change a bunch of data structures in the optimizer itself. Overall +we measured about 50% speed improvement in the optimizer, which reduces +the overall warmup time between 10% and 30%. The very +`obvious warmup benchmark`_ got a speedup from 4.5s to 3.5s so almost +30% improvement. Obviously the speedups on benchmarks would vastly +depend on how much warmup time is there in those benchmarks. We observed +annotation of pypy to decrease by about 30% and the overall translation +time by about 7%, so your mileage may vary. In fact in most cases there +should not be a visible difference if you're already achieving peak performance, +however wherever warmup is a problem there should be a modest speedup. + +.. _`obvious warmup benchmark`: https://bitbucket.org/pypy/benchmarks/src/fe2e89c0ae6846e3a8d4142106a4857e95f17da7/warmup/function_call2.py?at=default + +Cheers! +fijal & arigo + diff --git a/talk/ep2015/performance/Makefile b/talk/ep2015/performance/Makefile --- a/talk/ep2015/performance/Makefile +++ b/talk/ep2015/performance/Makefile @@ -5,7 +5,7 @@ # https://sourceforge.net/tracker/?func=detail&atid=422032&aid=1459707&group_id=38414 talk.pdf: talk.rst author.latex stylesheet.latex - python ../../bin/rst2beamer.py --stylesheet=stylesheet.latex --documentoptions=14pt talk.rst talk.latex || exit + python ../../bin/rst2beamer.py --stylesheet=stylesheet.latex --documentoptions=14pt --input-encoding=utf8 --output-encoding=utf8 talk.rst talk.latex || exit #/home/antocuni/.virtualenvs/rst2beamer/bin/python `which rst2beamer.py` --stylesheet=stylesheet.latex --documentoptions=14pt talk.rst talk.latex || exit sed 's/\\date{}/\\input{author.latex}/' -i talk.latex || exit #sed 's/\\maketitle/\\input{title.latex}/' -i talk.latex || exit diff --git a/talk/ep2015/performance/author.latex b/talk/ep2015/performance/author.latex --- a/talk/ep2015/performance/author.latex +++ b/talk/ep2015/performance/author.latex @@ -2,7 +2,7 @@ \title[Python and PyPy performance]{Python and PyPy performance\\(not) for dummies} \author[antocuni,fijal] -{Antonio Cuni and Maciej Fijalkowski} +{Antonio Cuni and Maciej Fijałkowski} \institute{EuroPython 2015} \date{July 21, 2015} diff --git a/talk/ep2015/performance/talk.pdf b/talk/ep2015/performance/talk.pdf index 874cebbd96fb24e3f93148dfd82afb0985fc7145..b17e14c7d49dc0a2c47900b50419cb90e1a31aae GIT binary patch [cut] diff --git a/talk/ep2015/performance/talk.rst b/talk/ep2015/performance/talk.rst --- a/talk/ep2015/performance/talk.rst +++ b/talk/ep2015/performance/talk.rst @@ -16,16 +16,6 @@ - http://baroquesoftware.com/ -About you -------------- - -- You are proficient in Python - -- Your Python program is slow - -- You want to make it fast(er) - - Optimization for dummies ------------------------- @@ -55,43 +45,37 @@ 2. How to address the problems +Part 1 +------ -Part 1 -------- - -* profiling - -* tools - +* identifying the slow spots What is performance? -------------------- -* you need something quantifiable by numbers +* something quantifiable by numbers * usually, time spent doing task X -* sometimes number of requests, latency, etc. +* number of requests, latency, etc. -* some statistical properties about that metric (average, minimum, maximum) +* statistical properties about that metric Do you have a performance problem? ---------------------------------- -* define what you're trying to measure +* what you're trying to measure -* measure it (production, benchmarks, etc.) +* means to measure it (production, benchmarks, etc.) -* see if Python is the cause here (if it's not, we can't help you, - but I'm sure someone can) +* is Python is the cause here? -* make sure you can change and test stuff quickly (e.g. benchmarks are better - than changing stuff in production) +* environment to quickly measure and check the results -* same as for debugging + - same as for debugging -We have a python problem ------------------------- +When Python is the problem +-------------------------- * tools, timers etc. @@ -106,7 +90,7 @@ * cProfile, runSnakeRun (high overhead) - event based profiler -* plop, vmprof - statistical profiler +* plop, vmprof - statistical profilers * cProfile & vmprof work on pypy @@ -121,8 +105,8 @@ * CPython, PyPy, possibly more virtual machines -why not just use gperftools? ----------------------------- +why not gperftools? +-------------------- * C stack does not contain python-level frames @@ -349,10 +333,19 @@ * avoid creating classes at runtime +Example +------- + +* ``map(operator.attrgetter('x'), list)`` + +vs + +* ``[x.x for x in list]`` + More about PyPy --------------- -* we are going to run a PyPy open space +* we are going to run a PyPy open space (tomorrow 18:00 @ A4) * come ask more questions From noreply at buildbot.pypy.org Tue Sep 8 18:27:59 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 18:27:59 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: wip: fix handling of weird __eq__ Message-ID: <20150908162759.4BB961C0FF6@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79548:7d1f31843f97 Date: 2015-09-08 17:52 +0200 http://bitbucket.org/pypy/pypy/changeset/7d1f31843f97/ Log: wip: fix handling of weird __eq__ diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py --- a/pypy/module/pypystm/stmdict.py +++ b/pypy/module/pypystm/stmdict.py @@ -16,7 +16,10 @@ PARRAY = lltype.Ptr(ARRAY) + def find_equal_item(space, array, w_key): + # result by this function is based on 'array'. If the entry + # changes, the result is stale. w_item = cast_gcref_to_instance(W_Root, array[0]) if space.eq_w(w_key, w_item): return 0 @@ -27,13 +30,12 @@ @jit.dont_look_inside def _run_next_iterations(space, array, w_key): i = 2 - limit = len(array) while True: w_item = cast_gcref_to_instance(W_Root, array[i]) - if space.eq_w(w_key, w_item): + if space.eq_w(w_key, w_item): # array may change here return i i += 2 - if i >= limit: + if i >= len(array): return -1 def ll_arraycopy(source, dest, source_start, dest_start, length): @@ -43,24 +45,37 @@ for i in range(length): dest[dest_start + i] = source[source_start + i] -def pop_from_entry(h, entry, space, w_key): +def pop_from_entry(h, space, w_key): + hkey = space.hash_w(w_key) + entry = h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) - if not array: - return None - i = find_equal_item(space, array, w_key) - if i < 0: - return None - # found - w_value = cast_gcref_to_instance(W_Root, array[i + 1]) - L = len(array) - 2 - if L == 0: - narray = lltype.nullptr(ARRAY) - else: - narray = lltype.malloc(ARRAY, L) - ll_arraycopy(array, narray, 0, 0, i) - ll_arraycopy(array, narray, i + 2, i, L - i) - h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return w_value + while True: + if not array: + return None + + i = find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + entry2 = h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue # not utopia yet + + if i < 0: + return None + # found + w_value = cast_gcref_to_instance(W_Root, array[i + 1]) + L = len(array) - 2 + if L == 0: + narray = lltype.nullptr(ARRAY) + else: + narray = lltype.malloc(ARRAY, L) + ll_arraycopy(array, narray, 0, 0, i) + ll_arraycopy(array, narray, i + 2, i, L - i) + h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return w_value + class W_STMDict(W_Root): @@ -70,63 +85,95 @@ def getitem_w(self, space, w_key): hkey = space.hash_w(w_key) - gcref = self.h.get(hkey) - array = lltype.cast_opaque_ptr(PARRAY, gcref) - if array: - i = find_equal_item(space, array, w_key) - if i >= 0: - return cast_gcref_to_instance(W_Root, array[i + 1]) - space.raise_key_error(w_key) + entry = self.h.lookup(hkey) + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + while True: + if array: + i = find_equal_item(space, array, w_key) + + if not space.type(w_key).compares_by_identity(): + # the world may have changed: + # if entry has changed, we are lost + # if array has changed, the result we got from find_equal_item + # is not trustworthy; should also imply entry!=entry2 + entry2 = self.h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue # not utopia yet + + if i >= 0: + return cast_gcref_to_instance(W_Root, array[i + 1]) + space.raise_key_error(w_key) def setitem_w(self, space, w_key, w_value): hkey = space.hash_w(w_key) entry = self.h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) - if array: - i = find_equal_item(space, array, w_key) - if i >= 0: - # already there, update the value - array[i + 1] = cast_instance_to_gcref(w_value) - return - L = len(array) - narray = lltype.malloc(ARRAY, L + 2) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 2) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - narray[L + 1] = cast_instance_to_gcref(w_value) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + while True: + if array: + i = find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + entry2 = self.h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue + + if i >= 0: + # already there, update the value + array[i + 1] = cast_instance_to_gcref(w_value) + return + L = len(array) + narray = lltype.malloc(ARRAY, L + 2) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 2) + L = 0 + narray[L] = cast_instance_to_gcref(w_key) + narray[L + 1] = cast_instance_to_gcref(w_value) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return def delitem_w(self, space, w_key): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - if pop_from_entry(self.h, entry, space, w_key) is None: + if pop_from_entry(self.h, space, w_key) is None: space.raise_key_error(w_key) def contains_w(self, space, w_key): hkey = space.hash_w(w_key) gcref = self.h.get(hkey) array = lltype.cast_opaque_ptr(PARRAY, gcref) - if array and find_equal_item(space, array, w_key) >= 0: - return space.w_True - return space.w_False + while True: + if array and find_equal_item(space, array, w_key) >= 0: + if not space.type(w_key).compares_by_identity(): + array2 = lltype.cast_opaque_ptr(PARRAY, self.h.get(hkey)) + if array2 != array: + array = array2 + continue + return space.w_True + return space.w_False @unwrap_spec(w_default=WrappedDefault(None)) def get_w(self, space, w_key, w_default): hkey = space.hash_w(w_key) gcref = self.h.get(hkey) array = lltype.cast_opaque_ptr(PARRAY, gcref) - if array: - i = find_equal_item(space, array, w_key) - if i >= 0: - return cast_gcref_to_instance(W_Root, array[i + 1]) - return w_default + while True: + if array: + i = find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + array2 = lltype.cast_opaque_ptr(PARRAY, self.h.get(hkey)) + if array2 != array: + array = array2 + continue + if i >= 0: + return cast_gcref_to_instance(W_Root, array[i + 1]) + return w_default def pop_w(self, space, w_key, w_default=None): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - w_value = pop_from_entry(self.h, entry, space, w_key) + w_value = pop_from_entry(self.h, space, w_key) if w_value is not None: return w_value elif w_default is not None: @@ -139,21 +186,29 @@ hkey = space.hash_w(w_key) entry = self.h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) - if array: - i = find_equal_item(space, array, w_key) - if i >= 0: - # already there, return the existing value - return cast_gcref_to_instance(W_Root, array[i + 1]) - L = len(array) - narray = lltype.malloc(ARRAY, L + 2) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 2) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - narray[L + 1] = cast_instance_to_gcref(w_default) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return w_default + while True: + if array: + i = find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + entry2 = self.h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue + if i >= 0: + # already there, return the existing value + return cast_gcref_to_instance(W_Root, array[i + 1]) + L = len(array) + narray = lltype.malloc(ARRAY, L + 2) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 2) + L = 0 + narray[L] = cast_instance_to_gcref(w_key) + narray[L + 1] = cast_instance_to_gcref(w_default) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return w_default def get_length(self): array, count = self.h.list() diff --git a/pypy/module/pypystm/test/test_stmdict.py b/pypy/module/pypystm/test/test_stmdict.py --- a/pypy/module/pypystm/test/test_stmdict.py +++ b/pypy/module/pypystm/test/test_stmdict.py @@ -116,3 +116,47 @@ res = d.pop(42.0, "foo") assert res == "bar" raises(KeyError, "d[42.0]") + + + def test_custom_evil_eq(self): + import pypystm + + class A(object): + depth = [] + def __hash__(self): + return 1 + def __eq__(self, other): + if not self.depth: + self.depth.append(1) + del d[a] + print "del a" + return self is other + d = pypystm.stmdict() + a = A() + b = A() + d[a] = "a" + d[b] = "b" # dels a + assert a not in d + assert b in d + + def test_custom_evil_eq2(self): + import pypystm + + class A(object): + depth = [] + def __hash__(self): + return 1 + def __eq__(self, other): + if not self.depth: + self.depth.append(1) + del d[a] + print "del a" + return self is other + d = pypystm.stmdict() + a = A() + b = A() + d[a] = "a" + assert d.get(b) is None + assert a not in d + assert b not in d + assert d.keys() == [] diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -298,20 +298,23 @@ class HashtableForTest(object): def __init__(self): - self._content = {} # dict {integer: GCREF} + self._content = {} # dict {integer: Entry(obj=GCREF)} def _cleanup_(self): raise Exception("cannot translate a prebuilt rstm.Hashtable object") def get(self, key): assert type(key) is int - return self._content.get(key, NULL_GCREF) + return self.lookup(key).object + # return self._content.get(key, NULL_GCREF) def set(self, key, value): assert type(key) is int assert lltype.typeOf(value) == llmemory.GCREF if value: - self._content[key] = value + entry = self.lookup(key) + entry._obj = value + # self._content[key] = value else: try: del self._content[key] @@ -319,10 +322,11 @@ pass def len(self): - return len(self._content) + items = [self.lookup(key) for key, v in self._content.items() if v.object != NULL_GCREF] + return len(items) def list(self): - items = [self.lookup(key) for key in self._content] + items = [self.lookup(key) for key, v in self._content.items() if v.object != NULL_GCREF] count = len(items) for i in range(3): items.append("additional garbage for testing") @@ -330,7 +334,7 @@ def lookup(self, key): assert type(key) is int - return EntryObjectForTest(self, key) + return self._content.setdefault(key, EntryObjectForTest(self, key)) def writeobj(self, entry, nvalue): assert isinstance(entry, EntryObjectForTest) @@ -341,9 +345,10 @@ self.hashtable = hashtable self.key = key self.index = r_uint(key) + self._obj = NULL_GCREF def _getobj(self): - return self.hashtable.get(self.key) + return self._obj def _setobj(self, nvalue): raise Exception("can't assign to the 'object' attribute:" " use h.writeobj() instead") From noreply at buildbot.pypy.org Tue Sep 8 18:28:01 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 8 Sep 2015 18:28:01 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: same changes for stmdict and some cleanup (that may be suboptimal for performance) Message-ID: <20150908162801.69B9C1C0FF6@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79549:196fe36e9067 Date: 2015-09-08 18:31 +0200 http://bitbucket.org/pypy/pypy/changeset/196fe36e9067/ Log: same changes for stmdict and some cleanup (that may be suboptimal for performance) diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py --- a/pypy/module/pypystm/stmdict.py +++ b/pypy/module/pypystm/stmdict.py @@ -17,7 +17,27 @@ -def find_equal_item(space, array, w_key): +def really_find_equal_item(space, h, w_key): + hkey = space.hash_w(w_key) + entry = h.lookup(hkey) + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + while True: + if not array: + return (entry, array, -1) + + i = _find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + entry2 = h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue + + return (entry, array, i) + + +def _find_equal_item(space, array, w_key): # result by this function is based on 'array'. If the entry # changes, the result is stale. w_item = cast_gcref_to_instance(W_Root, array[0]) @@ -27,15 +47,17 @@ return _run_next_iterations(space, array, w_key) return -1 + @jit.dont_look_inside def _run_next_iterations(space, array, w_key): i = 2 + limit = len(array) # fixed size while True: w_item = cast_gcref_to_instance(W_Root, array[i]) - if space.eq_w(w_key, w_item): # array may change here + if space.eq_w(w_key, w_item): return i i += 2 - if i >= len(array): + if i >= limit: return -1 def ll_arraycopy(source, dest, source_start, dest_start, length): @@ -46,35 +68,20 @@ dest[dest_start + i] = source[source_start + i] def pop_from_entry(h, space, w_key): - hkey = space.hash_w(w_key) - entry = h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - while True: - if not array: - return None - - i = find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - entry2 = h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue # not utopia yet - - if i < 0: - return None - # found - w_value = cast_gcref_to_instance(W_Root, array[i + 1]) - L = len(array) - 2 - if L == 0: - narray = lltype.nullptr(ARRAY) - else: - narray = lltype.malloc(ARRAY, L) - ll_arraycopy(array, narray, 0, 0, i) - ll_arraycopy(array, narray, i + 2, i, L - i) - h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return w_value + entry, array, i = really_find_equal_item(space, h, w_key) + if i < 0: + return None + # found + w_value = cast_gcref_to_instance(W_Root, array[i + 1]) + L = len(array) - 2 + if L == 0: + narray = lltype.nullptr(ARRAY) + else: + narray = lltype.malloc(ARRAY, L) + ll_arraycopy(array, narray, 0, 0, i) + ll_arraycopy(array, narray, i + 2, i, L - i) + h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return w_value @@ -84,28 +91,10 @@ self.h = rstm.create_hashtable() def getitem_w(self, space, w_key): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - while True: - if array: - i = find_equal_item(space, array, w_key) - - if not space.type(w_key).compares_by_identity(): - # the world may have changed: - # if entry has changed, we are lost - # if array has changed, the result we got from find_equal_item - # is not trustworthy; should also imply entry!=entry2 - entry2 = self.h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue # not utopia yet - - if i >= 0: - return cast_gcref_to_instance(W_Root, array[i + 1]) - space.raise_key_error(w_key) + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array and i >= 0: + return cast_gcref_to_instance(W_Root, array[i + 1]) + space.raise_key_error(w_key) def setitem_w(self, space, w_key, w_value): hkey = space.hash_w(w_key) @@ -113,15 +102,9 @@ array = lltype.cast_opaque_ptr(PARRAY, entry.object) while True: if array: - i = find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - entry2 = self.h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue - + entry, array, i = really_find_equal_item(space, self.h, w_key) + if not array: + continue if i >= 0: # already there, update the value array[i + 1] = cast_instance_to_gcref(w_value) @@ -142,35 +125,17 @@ space.raise_key_error(w_key) def contains_w(self, space, w_key): - hkey = space.hash_w(w_key) - gcref = self.h.get(hkey) - array = lltype.cast_opaque_ptr(PARRAY, gcref) - while True: - if array and find_equal_item(space, array, w_key) >= 0: - if not space.type(w_key).compares_by_identity(): - array2 = lltype.cast_opaque_ptr(PARRAY, self.h.get(hkey)) - if array2 != array: - array = array2 - continue - return space.w_True - return space.w_False + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array and i >= 0: + return space.w_True + return space.w_False @unwrap_spec(w_default=WrappedDefault(None)) def get_w(self, space, w_key, w_default): - hkey = space.hash_w(w_key) - gcref = self.h.get(hkey) - array = lltype.cast_opaque_ptr(PARRAY, gcref) - while True: - if array: - i = find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - array2 = lltype.cast_opaque_ptr(PARRAY, self.h.get(hkey)) - if array2 != array: - array = array2 - continue - if i >= 0: - return cast_gcref_to_instance(W_Root, array[i + 1]) - return w_default + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array and i >= 0: + return cast_gcref_to_instance(W_Root, array[i + 1]) + return w_default def pop_w(self, space, w_key, w_default=None): w_value = pop_from_entry(self.h, space, w_key) @@ -188,14 +153,9 @@ array = lltype.cast_opaque_ptr(PARRAY, entry.object) while True: if array: - i = find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - entry2 = self.h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue + entry, array, i = really_find_equal_item(space, self.h, w_key) + if not array: + continue if i >= 0: # already there, return the existing value return cast_gcref_to_instance(W_Root, array[i + 1]) diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py --- a/pypy/module/pypystm/stmset.py +++ b/pypy/module/pypystm/stmset.py @@ -17,7 +17,27 @@ PARRAY = lltype.Ptr(ARRAY) -def find_equal_item(space, array, w_key): + +def really_find_equal_item(space, h, w_key): + hkey = space.hash_w(w_key) + entry = h.lookup(hkey) + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + while True: + if not array: + return (entry, array, -1) + + i = _find_equal_item(space, array, w_key) + if not space.type(w_key).compares_by_identity(): + entry2 = h.lookup(hkey) + array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) + if array2 != array: + entry = entry2 + array = array2 + continue + + return (entry, array, i) + +def _find_equal_item(space, array, w_key): w_item = cast_gcref_to_instance(W_Root, array[0]) if space.eq_w(w_key, w_item): return 0 @@ -44,10 +64,8 @@ self.h = rstm.create_hashtable() def contains_w(self, space, w_key): - hkey = space.hash_w(w_key) - gcref = self.h.get(hkey) - array = lltype.cast_opaque_ptr(PARRAY, gcref) - if array and find_equal_item(space, array, w_key) >= 0: + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array and i >= 0: return space.w_True return space.w_False @@ -55,17 +73,22 @@ hkey = space.hash_w(w_key) entry = self.h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) - if array: - if find_equal_item(space, array, w_key) >= 0: - return # already there - L = len(array) - narray = lltype.malloc(ARRAY, L + 1) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 1) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + while True: + if array: + entry, array, i = really_find_equal_item(space, self.h, w_key) + if not array: + continue + if i >= 0: + return # already there + L = len(array) + narray = lltype.malloc(ARRAY, L + 1) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 1) + L = 0 + narray[L] = cast_instance_to_gcref(w_key) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return def try_remove(self, space, w_key): hkey = space.hash_w(w_key) @@ -73,8 +96,8 @@ array = lltype.cast_opaque_ptr(PARRAY, entry.object) if not array: return False - i = find_equal_item(space, array, w_key) - if i < 0: + entry, array, i = really_find_equal_item(space, self.h, w_key) + if not array or i < 0: return False # found L = len(array) - 1 diff --git a/pypy/module/pypystm/test/test_stmdict.py b/pypy/module/pypystm/test/test_stmdict.py --- a/pypy/module/pypystm/test/test_stmdict.py +++ b/pypy/module/pypystm/test/test_stmdict.py @@ -119,8 +119,6 @@ def test_custom_evil_eq(self): - import pypystm - class A(object): depth = [] def __hash__(self): @@ -131,6 +129,7 @@ del d[a] print "del a" return self is other + import pypystm d = pypystm.stmdict() a = A() b = A() @@ -140,8 +139,6 @@ assert b in d def test_custom_evil_eq2(self): - import pypystm - class A(object): depth = [] def __hash__(self): @@ -152,6 +149,7 @@ del d[a] print "del a" return self is other + import pypystm d = pypystm.stmdict() a = A() b = A() From noreply at buildbot.pypy.org Tue Sep 8 19:14:41 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 19:14:41 +0200 (CEST) Subject: [pypy-commit] pypy default: a failing test Message-ID: <20150908171441.546111C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79550:a189e6537fca Date: 2015-09-08 19:11 +0200 http://bitbucket.org/pypy/pypy/changeset/a189e6537fca/ Log: a failing test 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 @@ -8753,6 +8753,22 @@ """ self.optimize_loop(ops, expected) + def test_virtual_back_and_forth(self): + ops = """ + [p0] + p1 = getfield_gc_pure_r(p0, descr=bdescr) + ptemp = new_with_vtable(descr=nodesize) + setfield_gc(ptemp, p1, descr=nextdescr) + p2 = getfield_gc_r(ptemp, descr=nextdescr) + ix = getarrayitem_gc_pure_i(p2, 0, descr=arraydescr) + pfoo = getfield_gc_r(ptemp, descr=nextdescr) + guard_value(pfoo, ConstPtr(myarray)) [] + ifoo = int_add(ix, 13) + escape_n(ix) + jump(p0) + """ + self.optimize_loop(ops, ops) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass 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 @@ -135,6 +135,7 @@ node2addr = lltype.cast_opaque_ptr(llmemory.GCREF, node2) myptr = lltype.cast_opaque_ptr(llmemory.GCREF, node) mynode2 = lltype.malloc(NODE) + myarray = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(lltype.GcArray(lltype.Signed), 13)) mynode2.parent.typeptr = node_vtable myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode2) mynode3 = lltype.malloc(NODE2) From noreply at buildbot.pypy.org Tue Sep 8 19:14:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 19:14:43 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20150908171443.CA1AA1C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79551:aa12a967eb15 Date: 2015-09-08 19:14 +0200 http://bitbucket.org/pypy/pypy/changeset/aa12a967eb15/ Log: merge diff --git a/rpython/jit/backend/test/calling_convention_test.py b/rpython/jit/backend/test/calling_convention_test.py --- a/rpython/jit/backend/test/calling_convention_test.py +++ b/rpython/jit/backend/test/calling_convention_test.py @@ -373,6 +373,7 @@ [funcbox] + argslist, 'float', descr=calldescr) expected = func(*argvalues) + res = longlong.getrealfloat(res) assert abs(res - expected) < 0.0001 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -680,7 +680,7 @@ args = [op.getarg(1), op.getarg(2)] loc1 = self.load_xmm_aligned_16_bytes(args[0]) loc2 = self.load_xmm_aligned_16_bytes(args[1], args) - tmpxvar = TempBox() + tmpxvar = TempVar() loc3 = self.xrm.force_allocate_reg(tmpxvar, args) self.xrm.possibly_free_var(tmpxvar) loc0 = self.rm.force_allocate_reg(op, need_lower_byte=True) @@ -691,11 +691,11 @@ box = op.getarg(2) if not isinstance(box, ConstFloat): return False - if box.getlonglong() != 0: + if box.getfloat() != 0.0: # NaNs are also != 0.0 return False - # "x < 0" + # "x < 0.0" or maybe "x < -0.0" which is the same box = op.getarg(1) - assert isinstance(box, BoxFloat) + assert box.type == FLOAT loc1 = self.xrm.make_sure_var_in_reg(box) loc0 = self.rm.force_allocate_reg(op) self.perform_llong(op, [loc1], loc0) @@ -720,7 +720,7 @@ loc2 = None # unused else: loc1 = self.rm.make_sure_var_in_reg(box) - tmpxvar = TempBox() + tmpxvar = TempVar() loc2 = self.xrm.force_allocate_reg(tmpxvar, [op]) self.xrm.possibly_free_var(tmpxvar) self.perform_llong(op, [loc1, loc2], loc0) diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -83,10 +83,6 @@ def getfloat(self): return longlong.getrealfloat(self.getfloatstorage()) - def getlonglong(self): - assert longlong.supports_longlong - return self.getfloatstorage() - def getref_base(self): raise NotImplementedError @@ -622,12 +618,12 @@ elif isinstance(value, bool): assert op.type == 'i' op.setint(int(value)) - elif isinstance(value, float): - assert op.type == 'f' - op.setfloatstorage(value) elif lltype.typeOf(value) == lltype.Signed: assert op.type == 'i' op.setint(value) + elif lltype.typeOf(value) is longlong.FLOATSTORAGE: + assert op.type == 'f' + op.setfloatstorage(value) else: assert lltype.typeOf(value) == llmemory.GCREF assert op.type == 'r' diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -131,7 +131,7 @@ return 'ConstPtr(ptr' + str(mv) + ')' return 'ConstPtr(null)' elif isinstance(arg, ConstFloat): - return str(arg.getfloatstorage()) + return str(arg.getfloat()) elif arg is None: return 'None' elif arg.type == 'i': 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 @@ -2,7 +2,7 @@ import py -from rpython.jit.codewriter import heaptracker +from rpython.jit.codewriter import heaptracker, longlong from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr from rpython.jit.metainterp import history, compile, resume, executor, jitexc @@ -3013,7 +3013,7 @@ rop.GETARRAYITEM_RAW_F, [box_exchange_buffer, ConstInt(ofs // itemsize)], - 0.0, descr) + longlong.ZEROF, descr) else: assert kind == 'v' continue diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -409,7 +409,7 @@ type = 'f' - _resfloat = 0.0 + _resfloat = longlong.ZEROF def getfloatstorage(self): return self._resfloat From noreply at buildbot.pypy.org Tue Sep 8 20:10:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 20:10:08 +0200 (CEST) Subject: [pypy-commit] pypy default: fix Message-ID: <20150908181008.1BDEE1C0F0C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79552:b46f34f3f2a9 Date: 2015-09-08 20:10 +0200 http://bitbucket.org/pypy/pypy/changeset/b46f34f3f2a9/ Log: fix 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 @@ -708,6 +708,12 @@ def get_known_class(self, cpu): if not self._const.nonnull(): return None + if cpu.supports_guard_gc_type: + # we should only be called on an unknown box here from + # virtualstate.py, which is only when the cpu supports + # guard_gc_type + if not cpu.check_is_object(self._const.getref_base()): + return None return cpu.ts.cls_of_box(self._const) def same_info(self, other): 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 @@ -8767,6 +8767,11 @@ escape_n(ix) jump(p0) """ + ops = """ + [] + escape_n(0) + jump() + """ self.optimize_loop(ops, ops) 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 @@ -135,7 +135,7 @@ node2addr = lltype.cast_opaque_ptr(llmemory.GCREF, node2) myptr = lltype.cast_opaque_ptr(llmemory.GCREF, node) mynode2 = lltype.malloc(NODE) - myarray = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(lltype.GcArray(lltype.Signed), 13)) + myarray = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(lltype.GcArray(lltype.Signed), 13, zero=True)) mynode2.parent.typeptr = node_vtable myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode2) mynode3 = lltype.malloc(NODE2) From noreply at buildbot.pypy.org Tue Sep 8 21:30:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 21:30:14 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: work on the blog post Message-ID: <20150908193014.B62701C0F0C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5548:c5dc8aeb1a3e Date: 2015-09-08 21:30 +0200 http://bitbucket.org/pypy/extradoc/changeset/c5dc8aeb1a3e/ Log: work on the blog post diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -44,7 +44,13 @@ should not be a visible difference if you're already achieving peak performance, however wherever warmup is a problem there should be a modest speedup. +Of course, as usual with the large refactoring of a crucial piece of PyPy, +there are expected to be bugs. We are going to wait for the default to stabilize +and you should see warmup improvements in the next release. If you're not afraid +to try, `nightlies`_ will already have them. + .. _`obvious warmup benchmark`: https://bitbucket.org/pypy/benchmarks/src/fe2e89c0ae6846e3a8d4142106a4857e95f17da7/warmup/function_call2.py?at=default +.. _`nightlies`: http://buildbot.pypy.org/nightly/trunk Cheers! fijal & arigo From noreply at buildbot.pypy.org Tue Sep 8 22:20:45 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 22:20:45 +0200 (CEST) Subject: [pypy-commit] pypy default: well spotted amaury Message-ID: <20150908202045.A3B791C0F0C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79553:42727da17a95 Date: 2015-09-08 22:20 +0200 http://bitbucket.org/pypy/pypy/changeset/42727da17a95/ Log: well spotted amaury 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 @@ -8767,12 +8767,14 @@ escape_n(ix) jump(p0) """ - ops = """ - [] - escape_n(0) - jump() - """ - self.optimize_loop(ops, ops) + expected = """ + [p0, p1, i2] + # XXX why is Const not a part of virtualstate??? + guard_value(p1, ConstPtr(myarray)) [] + escape_n(i2) + jump(p0, ConstPtr(myarray), 0) + """ + self.optimize_loop(ops, expected) class TestLLtype(OptimizeOptTest, LLtypeMixin): From noreply at buildbot.pypy.org Tue Sep 8 22:47:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 8 Sep 2015 22:47:43 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add the Message-ID: <20150908204743.636391C0F0C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5549:0eedae805b2d Date: 2015-09-08 22:48 +0200 http://bitbucket.org/pypy/extradoc/changeset/0eedae805b2d/ Log: add the diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -1,6 +1,7 @@ Hello everyone! -I'm very pleased to announce that we've just managed to merge optresult branch. +I'm very pleased to announce that we've just managed to merge +the optresult branch. Under this cryptic name is the biggest JIT refactoring we've done in a couple years, mostly focused on the warmup time and memory impact of PyPy. From noreply at buildbot.pypy.org Tue Sep 8 22:56:42 2015 From: noreply at buildbot.pypy.org (stefanor) Date: Tue, 8 Sep 2015 22:56:42 +0200 (CEST) Subject: [pypy-commit] pypy default: mhlib test requires some extra modules. Also, it fails Message-ID: <20150908205642.B58BE1C0F0C@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r79554:721a9fdb198c Date: 2015-09-08 13:53 -0700 http://bitbucket.org/pypy/pypy/changeset/721a9fdb198c/ Log: mhlib test requires some extra modules. Also, it fails diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -303,7 +303,7 @@ RegrTest('test_memoryio.py'), RegrTest('test_memoryview.py'), RegrTest('test_md5.py'), - RegrTest('test_mhlib.py'), + RegrTest('test_mhlib.py', usemodules='binascii struct'), RegrTest('test_mimetools.py'), RegrTest('test_mimetypes.py'), RegrTest('test_MimeWriter.py', core=False, usemodules='binascii'), From noreply at buildbot.pypy.org Wed Sep 9 10:00:16 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 9 Sep 2015 10:00:16 +0200 (CEST) Subject: [pypy-commit] pypy default: Seems the process deadlocks if you call pypy_init_threads() before Message-ID: <20150909080016.A71EC1C0EEA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79555:e12aa509d33d Date: 2015-09-09 10:00 +0200 http://bitbucket.org/pypy/pypy/changeset/e12aa509d33d/ Log: Seems the process deadlocks if you call pypy_init_threads() before pypy_setup_home() diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -20,10 +20,6 @@ It initializes the RPython/PyPy GC and does a bunch of necessary startup code. This function cannot fail. -.. function:: void pypy_init_threads(void); - - Initialize threads. Only need to be called if there are any threads involved - .. function:: int pypy_setup_home(char* home, int verbose); This function searches the PyPy standard library starting from the given @@ -38,6 +34,11 @@ Function returns 0 on success or -1 on failure, can be called multiple times until the library is found. +.. function:: void pypy_init_threads(void); + + Initialize threads. Only need to be called if there are any threads involved. + *Must be called after pypy_setup_home()* + .. function:: int pypy_execute_source(char* source); Execute the Python source code given in the ``source`` argument. In case of From noreply at buildbot.pypy.org Wed Sep 9 10:14:03 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 9 Sep 2015 10:14:03 +0200 (CEST) Subject: [pypy-commit] pypy default: Add cast_int_to_float in this test. Passes Message-ID: <20150909081403.E3DFB1C02C7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79556:c7ce70d5b4a1 Date: 2015-09-09 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/c7ce70d5b4a1/ Log: Add cast_int_to_float in this test. Passes diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py b/rpython/jit/backend/llsupport/test/ztranslation_test.py --- a/rpython/jit/backend/llsupport/test/ztranslation_test.py +++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py @@ -26,6 +26,7 @@ # - profiler # - full optimizer # - floats neg and abs + # - cast_int_to_float # - llexternal with macro=True class BasicFrame(object): @@ -69,6 +70,7 @@ frame.i -= 1 j *= -0.712 if j + (-j): raise ValueError + j += frame.i k = myabs1(myabs2(j)) if k - abs(j): raise ValueError if k - abs(-j): raise ValueError From noreply at buildbot.pypy.org Wed Sep 9 10:16:49 2015 From: noreply at buildbot.pypy.org (vext01) Date: Wed, 9 Sep 2015 10:16:49 +0200 (CEST) Subject: [pypy-commit] pypy detect_egd2: Detect RAND_egd() and make ssl.RAND_egd() raise if not found. Message-ID: <20150909081649.8C2051C02C7@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: detect_egd2 Changeset: r79557:506d9ba2b5f8 Date: 2015-09-09 09:16 +0100 http://bitbucket.org/pypy/pypy/changeset/506d9ba2b5f8/ Log: Detect RAND_egd() and make ssl.RAND_egd() raise if not found. diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -241,20 +241,26 @@ res = libssl_RAND_status() return space.wrap(res) - @unwrap_spec(path=str) - def RAND_egd(space, path): - """RAND_egd(path) -> bytes + if HAVE_OPENSSL_RAND_EGD: + @unwrap_spec(path=str) + def RAND_egd(space, path): + """RAND_egd(path) -> bytes - Queries the entropy gather daemon (EGD) on socket path. Returns number - of bytes read. Raises socket.sslerror if connection to EGD fails or - if it does provide enough data to seed PRNG.""" - with rffi.scoped_str2charp(path) as socket_path: - bytes = libssl_RAND_egd(socket_path) - if bytes == -1: - raise ssl_error(space, - "EGD connection failed or EGD did not return " - "enough data to seed the PRNG") - return space.wrap(bytes) + Queries the entropy gather daemon (EGD) on socket path. Returns number + of bytes read. Raises socket.sslerror if connection to EGD fails or + if it does provide enough data to seed PRNG.""" + with rffi.scoped_str2charp(path) as socket_path: + bytes = libssl_RAND_egd(socket_path) + if bytes == -1: + raise ssl_error(space, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG") + return space.wrap(bytes) + else: + # Dummy func for platforms missing RAND_egd(). Most likely LibreSSL. + @unwrap_spec(path=str) + def RAND_egd(space, path): + raise ssl_error(space, "RAND_egd unavailable") class _SSLSocket(W_Root): diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -264,6 +264,9 @@ OPENSSL_NO_ECDH = True HAS_ALPN = OPENSSL_VERSION_NUMBER >= 0x1000200fL and not OPENSSL_NO_TLSEXT +HAVE_OPENSSL_RAND_EGD = rffi_platform.has('RAND_egd("/")', + '#include ', + libraries=['ssl', 'crypto']) def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci @@ -288,7 +291,8 @@ if HAVE_OPENSSL_RAND: ssl_external('RAND_add', [rffi.CCHARP, rffi.INT, rffi.DOUBLE], lltype.Void) ssl_external('RAND_status', [], rffi.INT) - ssl_external('RAND_egd', [rffi.CCHARP], rffi.INT) + if HAVE_OPENSSL_RAND_EGD: + ssl_external('RAND_egd', [rffi.CCHARP], rffi.INT) ssl_external('SSL_CTX_new', [SSL_METHOD], SSL_CTX) ssl_external('SSL_get_SSL_CTX', [SSL], SSL_CTX) ssl_external('SSL_set_SSL_CTX', [SSL, SSL_CTX], SSL_CTX) diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -17,12 +17,15 @@ # # Helpers for simple cases -def eci_from_header(c_header_source, include_dirs=None): +def eci_from_header(c_header_source, include_dirs=None, libraries=None): if include_dirs is None: include_dirs = [] + if libraries is None: + libraries = [] return ExternalCompilationInfo( post_include_bits=[c_header_source], - include_dirs=include_dirs + include_dirs=include_dirs, + libraries=libraries, ) def getstruct(name, c_header_source, interesting_fields): @@ -75,9 +78,10 @@ CConfig._compilation_info_.includes = includes return configure(CConfig)['RESULT'] -def has(name, c_header_source, include_dirs=None): +def has(name, c_header_source, include_dirs=None, libraries=None): class CConfig: - _compilation_info_ = eci_from_header(c_header_source, include_dirs) + _compilation_info_ = \ + eci_from_header(c_header_source, include_dirs, libraries) HAS = Has(name) return configure(CConfig)['HAS'] From noreply at buildbot.pypy.org Wed Sep 9 10:32:27 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 9 Sep 2015 10:32:27 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit: test and fix Message-ID: <20150909083227.4409D1C02C7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79558:dc417bfabae3 Date: 2015-09-09 10:32 +0200 http://bitbucket.org/pypy/pypy/changeset/dc417bfabae3/ Log: 32-bit: test and fix diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -166,7 +166,7 @@ return ConstInt(value) elif isinstance(value, bool): return ConstInt(int(value)) - elif isinstance(value, float): + elif lltype.typeOf(value) == longlong.FLOATSTORAGE: return ConstFloat(value) else: assert lltype.typeOf(value) == llmemory.GCREF diff --git a/rpython/jit/metainterp/test/test_float.py b/rpython/jit/metainterp/test/test_float.py --- a/rpython/jit/metainterp/test/test_float.py +++ b/rpython/jit/metainterp/test/test_float.py @@ -66,6 +66,16 @@ res = self.interp_operations(g, [-12345]) assert type(res) is float and res == -12345.0 + def test_cast_int_to_float_constant(self): + def h(i): + if i < 10: + i = 10 + return i + def g(i): + return float(h(i)) + res = self.interp_operations(g, [-12345]) + assert type(res) is float and res == 10.0 + def test_cast_uint_to_float(self): def g(i): return float(r_uint(i)) From noreply at buildbot.pypy.org Wed Sep 9 10:37:26 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 10:37:26 +0200 (CEST) Subject: [pypy-commit] pypy default: skip the checks on arm Message-ID: <20150909083726.DE73B1C02C7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79559:f67ec99dddfb Date: 2015-09-09 10:37 +0200 http://bitbucket.org/pypy/pypy/changeset/f67ec99dddfb/ Log: skip the checks on arm diff --git a/rpython/jit/backend/arm/test/support.py b/rpython/jit/backend/arm/test/support.py --- a/rpython/jit/backend/arm/test/support.py +++ b/rpython/jit/backend/arm/test/support.py @@ -10,6 +10,7 @@ class JitARMMixin(support.LLJitMixin): type_system = 'lltype' CPUClass = getcpuclass() + basic = True def check_jumps(self, maxcount): pass From noreply at buildbot.pypy.org Wed Sep 9 11:45:19 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 9 Sep 2015 11:45:19 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: blindly try to improve performance of stmdict/stmset Message-ID: <20150909094519.B48ED1C02C7@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79560:4850638fd47d Date: 2015-09-09 11:49 +0200 http://bitbucket.org/pypy/pypy/changeset/4850638fd47d/ Log: blindly try to improve performance of stmdict/stmset diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py --- a/pypy/module/pypystm/stmdict.py +++ b/pypy/module/pypystm/stmdict.py @@ -16,23 +16,39 @@ PARRAY = lltype.Ptr(ARRAY) - +# XXX: should have identity-dict strategy def really_find_equal_item(space, h, w_key): hkey = space.hash_w(w_key) entry = h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) + if not array: + return (entry, array, -1) + if space.type(w_key).compares_by_identity(): + # fastpath + return (entry, array, _find_equal_item(space, array, w_key)) + # slowpath + return _really_find_equal_item_loop(space, h, w_key, entry, array, hkey) + + at jit.dont_look_inside +def _really_find_equal_item_loop(space, h, w_key, entry, array, hkey): + assert not space.type(w_key).compares_by_identity() # assume it stays that way while True: - if not array: - return (entry, array, -1) - + assert array i = _find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - entry2 = h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue + # custom __eq__ may have been called in _find_equal_item() + # + # Only if entry.object changed during the call to _find_equal_item() + # we have to re-lookup the entry. This is ok since entry.object=array!=NULL + # when we enter here and therefore, entry can only be thrown out of + # the hashtable if it gets NULLed somehow, thus, changing entry.object. + array2 = lltype.cast_opaque_ptr(PARRAY, entry.object) + if array != array2: + # re-get entry (and array) + entry = h.lookup(hkey) + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + if not array: + return (entry, array, -1) + continue return (entry, array, i) @@ -69,7 +85,7 @@ def pop_from_entry(h, space, w_key): entry, array, i = really_find_equal_item(space, h, w_key) - if i < 0: + if i < 0: # or not array return None # found w_value = cast_gcref_to_instance(W_Root, array[i + 1]) @@ -97,28 +113,21 @@ space.raise_key_error(w_key) def setitem_w(self, space, w_key, w_value): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - while True: - if array: - entry, array, i = really_find_equal_item(space, self.h, w_key) - if not array: - continue - if i >= 0: - # already there, update the value - array[i + 1] = cast_instance_to_gcref(w_value) - return - L = len(array) - narray = lltype.malloc(ARRAY, L + 2) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 2) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - narray[L + 1] = cast_instance_to_gcref(w_value) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array: + if i >= 0: + # already there, update the value + array[i + 1] = cast_instance_to_gcref(w_value) + return + L = len(array) + narray = lltype.malloc(ARRAY, L + 2) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 2) + L = 0 + narray[L] = cast_instance_to_gcref(w_key) + narray[L + 1] = cast_instance_to_gcref(w_value) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) def delitem_w(self, space, w_key): if pop_from_entry(self.h, space, w_key) is None: @@ -148,27 +157,22 @@ @unwrap_spec(w_default=WrappedDefault(None)) def setdefault_w(self, space, w_key, w_default): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - while True: - if array: - entry, array, i = really_find_equal_item(space, self.h, w_key) - if not array: - continue - if i >= 0: - # already there, return the existing value - return cast_gcref_to_instance(W_Root, array[i + 1]) - L = len(array) - narray = lltype.malloc(ARRAY, L + 2) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 2) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - narray[L + 1] = cast_instance_to_gcref(w_default) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return w_default + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array: + if i >= 0: + # already there, return the existing value + return cast_gcref_to_instance(W_Root, array[i + 1]) + L = len(array) + narray = lltype.malloc(ARRAY, L + 2) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 2) + L = 0 + narray[L] = cast_instance_to_gcref(w_key) + narray[L + 1] = cast_instance_to_gcref(w_default) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) + return w_default + def get_length(self): array, count = self.h.list() diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py --- a/pypy/module/pypystm/stmset.py +++ b/pypy/module/pypystm/stmset.py @@ -17,27 +17,46 @@ PARRAY = lltype.Ptr(ARRAY) - +# XXX: should have identity-dict strategy def really_find_equal_item(space, h, w_key): hkey = space.hash_w(w_key) entry = h.lookup(hkey) array = lltype.cast_opaque_ptr(PARRAY, entry.object) + if not array: + return (entry, array, -1) + if space.type(w_key).compares_by_identity(): + # fastpath + return (entry, array, _find_equal_item(space, array, w_key)) + # slowpath + return _really_find_equal_item_loop(space, h, w_key, entry, array, hkey) + + at jit.dont_look_inside +def _really_find_equal_item_loop(space, h, w_key, entry, array, hkey): + assert not space.type(w_key).compares_by_identity() # assume it stays that way while True: - if not array: - return (entry, array, -1) - + assert array i = _find_equal_item(space, array, w_key) - if not space.type(w_key).compares_by_identity(): - entry2 = h.lookup(hkey) - array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object) - if array2 != array: - entry = entry2 - array = array2 - continue + # custom __eq__ may have been called in _find_equal_item() + # + # Only if entry.object changed during the call to _find_equal_item() + # we have to re-lookup the entry. This is ok since entry.object=array!=NULL + # when we enter here and therefore, entry can only be thrown out of + # the hashtable if it gets NULLed somehow, thus, changing entry.object. + array2 = lltype.cast_opaque_ptr(PARRAY, entry.object) + if array != array2: + # re-get entry (and array) + entry = h.lookup(hkey) + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + if not array: + return (entry, array, -1) + continue return (entry, array, i) + def _find_equal_item(space, array, w_key): + # result by this function is based on 'array'. If the entry + # changes, the result is stale. w_item = cast_gcref_to_instance(W_Root, array[0]) if space.eq_w(w_key, w_item): return 0 @@ -45,6 +64,7 @@ return _run_next_iterations(space, array, w_key) return -1 + @jit.dont_look_inside def _run_next_iterations(space, array, w_key): i = 1 @@ -70,32 +90,21 @@ return space.w_False def add_w(self, space, w_key): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - while True: - if array: - entry, array, i = really_find_equal_item(space, self.h, w_key) - if not array: - continue - if i >= 0: - return # already there - L = len(array) - narray = lltype.malloc(ARRAY, L + 1) - ll_arraycopy(array, narray, 0, 0, L) - else: - narray = lltype.malloc(ARRAY, 1) - L = 0 - narray[L] = cast_instance_to_gcref(w_key) - self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) - return + entry, array, i = really_find_equal_item(space, self.h, w_key) + if array: + if i >= 0: + return # already there + L = len(array) + narray = lltype.malloc(ARRAY, L + 1) + ll_arraycopy(array, narray, 0, 0, L) + else: + narray = lltype.malloc(ARRAY, 1) + L = 0 + + narray[L] = cast_instance_to_gcref(w_key) + self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray)) def try_remove(self, space, w_key): - hkey = space.hash_w(w_key) - entry = self.h.lookup(hkey) - array = lltype.cast_opaque_ptr(PARRAY, entry.object) - if not array: - return False entry, array, i = really_find_equal_item(space, self.h, w_key) if not array or i < 0: return False diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -317,6 +317,11 @@ # self._content[key] = value else: try: + # set entry to value (since somebody may still have + # a reference to it), then delete it from the table, + # as that may happen *anytime* if _obj==NULL + entry = self.lookup(key) + entry._obj = value del self._content[key] except KeyError: pass From noreply at buildbot.pypy.org Wed Sep 9 13:43:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 13:43:13 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: (fijal, tos9) reshuffle and improve Message-ID: <20150909114313.A844C1C0325@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5550:6d2003548bf4 Date: 2015-09-09 13:43 +0200 http://bitbucket.org/pypy/extradoc/changeset/6d2003548bf4/ Log: (fijal, tos9) reshuffle and improve diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -10,7 +10,8 @@ on the peak performance with some consideration towards memory usage, but without serious consideration towards warmup time. This means we accumulated quite a bit of technical debt over time that we're trying, with difficulty, -to address right now. +to address right now. This branch mostly does not affect the peak performance +- it should however help you with short-living scripts, like test runs. The branch does "one" thing - it changes the underlaying model of how operations are represented during the tracing and optimizations. Let's consider a simple @@ -33,17 +34,17 @@ example, ``i2`` would refer to its producer - ``i2 = int_add(i0, i1)`` with arguments getting special treatment. -That alone reduces the GC pressure slightly, but we went an extra mile -to change a bunch of data structures in the optimizer itself. Overall +That alone reduces the GC pressure slightly, but a reduced number +of instances also lets us store references on them directly instead +of going through expensive dictionaries, which were used to store optimizing +information about the boxes. Overall we measured about 50% speed improvement in the optimizer, which reduces the overall warmup time between 10% and 30%. The very `obvious warmup benchmark`_ got a speedup from 4.5s to 3.5s so almost 30% improvement. Obviously the speedups on benchmarks would vastly depend on how much warmup time is there in those benchmarks. We observed annotation of pypy to decrease by about 30% and the overall translation -time by about 7%, so your mileage may vary. In fact in most cases there -should not be a visible difference if you're already achieving peak performance, -however wherever warmup is a problem there should be a modest speedup. +time by about 7%, so your mileage may vary. Of course, as usual with the large refactoring of a crucial piece of PyPy, there are expected to be bugs. We are going to wait for the default to stabilize From noreply at buildbot.pypy.org Wed Sep 9 14:42:18 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 14:42:18 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: (tos9) english Message-ID: <20150909124218.889A51C0325@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5551:4ba135bb3c2b Date: 2015-09-09 14:42 +0200 http://bitbucket.org/pypy/extradoc/changeset/4ba135bb3c2b/ Log: (tos9) english diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -7,15 +7,15 @@ To understand why we did that, let's look back in time - back when we got the first working JIT prototype in 2009 we were focused exclusively -on the peak performance with some consideration towards memory usage, but +on achieving peak performance with some consideration towards memory usage, but without serious consideration towards warmup time. This means we accumulated quite a bit of technical debt over time that we're trying, with difficulty, to address right now. This branch mostly does not affect the peak performance - it should however help you with short-living scripts, like test runs. -The branch does "one" thing - it changes the underlaying model of how operations -are represented during the tracing and optimizations. Let's consider a simple -loop like that:: +The branch does "one" thing - it changes the underlying model of how operations +are represented during tracing and optimizations. Let's consider a simple +loop like:: [i0, i1] i2 = int_add(i0, i1) @@ -27,10 +27,10 @@ The original representation would allocate a ``Box`` for each of ``i0`` - ``i4`` and then store those boxes in instances of ``ResOperation``. The list of such operations would then go to the optimizer. Those lists are big - we usually -remove ``90%`` of them during optimizations, but they can be couple thousand -elements. Overall allocating those big lists takes a toll on warmup time, +remove ``90%`` of them during optimizations, but they can be a couple thousand +elements. Overall, allocating those big lists takes a toll on warmup time, especially due to the GC pressure. The branch removes the existance of ``Box`` -completely, instead using link to ``ResOperation`` itself. So say in the above +completely, instead using a link to ``ResOperation`` itself. So say in the above example, ``i2`` would refer to its producer - ``i2 = int_add(i0, i1)`` with arguments getting special treatment. @@ -40,15 +40,16 @@ information about the boxes. Overall we measured about 50% speed improvement in the optimizer, which reduces the overall warmup time between 10% and 30%. The very -`obvious warmup benchmark`_ got a speedup from 4.5s to 3.5s so almost +`obvious warmup benchmark`_ got a speedup from 4.5s to 3.5s, almost 30% improvement. Obviously the speedups on benchmarks would vastly depend on how much warmup time is there in those benchmarks. We observed -annotation of pypy to decrease by about 30% and the overall translation +annotation of pypy to decreasing by about 30% and the overall translation time by about 7%, so your mileage may vary. Of course, as usual with the large refactoring of a crucial piece of PyPy, -there are expected to be bugs. We are going to wait for the default to stabilize -and you should see warmup improvements in the next release. If you're not afraid +there are expected to be bugs. We are going to wait for the default branch +to stabilize +so you should see warmup improvements in the next release. If you're not afraid to try, `nightlies`_ will already have them. .. _`obvious warmup benchmark`: https://bitbucket.org/pypy/benchmarks/src/fe2e89c0ae6846e3a8d4142106a4857e95f17da7/warmup/function_call2.py?at=default From noreply at buildbot.pypy.org Wed Sep 9 14:50:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 14:50:08 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: work on stuff Message-ID: <20150909125008.719391C0EEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5552:2f0514a10634 Date: 2015-09-09 14:50 +0200 http://bitbucket.org/pypy/extradoc/changeset/2f0514a10634/ Log: work on stuff diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -13,6 +13,58 @@ to address right now. This branch mostly does not affect the peak performance - it should however help you with short-living scripts, like test runs. +To see how much of a problem warmup is for your program, you can run your +program with ``PYPYLOG=jit-summary:-`` environment variable set. +This should show you something like this:: + + (pypy-optresult)fijal at hermann:~/src/botbot-web$ PYPYLOG=jit-summary:- python orm.py 1500 + [d195a2fcecc] {jit-summary + Tracing: 781 2.924965 + Backend: 737 0.722710 + TOTAL: 35.912011 + ops: 1860596 + recorded ops: 493138 + calls: 81022 + guards: 131238 + opt ops: 137263 + opt guards: 35166 + forcings: 4196 + abort: trace too long: 22 + abort: compiling: 0 + abort: vable escape: 22 + abort: bad loop: 0 + abort: force quasi-immut: 0 + nvirtuals: 183672 + nvholes: 25797 + nvreused: 116131 + Total # of loops: 193 + Total # of bridges: 575 + Freed # of loops: 6 + Freed # of bridges: 75 + [d195a48de18] jit-summary} + +This means that the total (wall clock) time was 35.9s, out of which we spent +2.9s tracing 781 loops and 0.72s compiling them. The remaining couple were +aborted (trace too long is normal, vable escape means someone called +``sys._getframe()`` or equivalent). You can do the following things: + +* compare the numbers with ``pypy --jit off`` and see at which number of + iterations ``pypy`` jit kicks in + +* play with the thresholds: + ``pypy --jit threshold=500,function_threshold=400,trace_eagerness=50`` was + much better in this example. What this does is to lower the threshold + for tracing loops from default of 1039 to 400, threshold for tracing + functions from the start from 1619 to 500 and threshold for tracing bridges + from 200 to 50. Bridges are "alternative paths" that JIT did not take that + are being additionally traced. We believe in sane defaults, so we'll try + to improve upon those numbers, but generally speaking there is no one-size + fits all here. + +* if the tracing/backend time stays high, come and complain to us with + benchmarks, we'll try to look at them + + The branch does "one" thing - it changes the underlying model of how operations are represented during tracing and optimizations. Let's consider a simple loop like:: From noreply at buildbot.pypy.org Wed Sep 9 14:54:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 14:54:53 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: expand Message-ID: <20150909125453.2A8291C0EEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r5553:154475eba91b Date: 2015-09-09 14:55 +0200 http://bitbucket.org/pypy/extradoc/changeset/154475eba91b/ Log: expand diff --git a/blog/draft/warmup-improvements.rst b/blog/draft/warmup-improvements.rst --- a/blog/draft/warmup-improvements.rst +++ b/blog/draft/warmup-improvements.rst @@ -13,6 +13,12 @@ to address right now. This branch mostly does not affect the peak performance - it should however help you with short-living scripts, like test runs. +We identified warmup time to be one of the major pain points for pypy users, +along with memory impact and compatibility issues with CPython C extension +world. While we can't address all the issues at once, we're trying to address +the first two in the work contributing to this blog post. I will write +a separate article on the last item separately. + To see how much of a problem warmup is for your program, you can run your program with ``PYPYLOG=jit-summary:-`` environment variable set. This should show you something like this:: @@ -64,6 +70,18 @@ * if the tracing/backend time stays high, come and complain to us with benchmarks, we'll try to look at them +Warmup, as a number, is notoriously hard to measure. It's a combination of: + +* pypy running interpreter before jitting + +* pypy needing time to JIT the traces + +* additional memory allocations needed during tracing to accomodate bookkeeping + data + +* exiting and entering assembler until there is enough coverage of assembler + +We're working hard on making a better assesment at this number, stay tuned :-) The branch does "one" thing - it changes the underlying model of how operations are represented during tracing and optimizations. Let's consider a simple @@ -104,6 +122,9 @@ so you should see warmup improvements in the next release. If you're not afraid to try, `nightlies`_ will already have them. +We're hoping to continue improving upon warmup time and memory impact in the +future, stay tuned for improvements. + .. _`obvious warmup benchmark`: https://bitbucket.org/pypy/benchmarks/src/fe2e89c0ae6846e3a8d4142106a4857e95f17da7/warmup/function_call2.py?at=default .. _`nightlies`: http://buildbot.pypy.org/nightly/trunk From noreply at buildbot.pypy.org Wed Sep 9 15:30:46 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 9 Sep 2015 15:30:46 +0200 (CEST) Subject: [pypy-commit] pypy default: be a bit more diligent what do we inherit in virtuals Message-ID: <20150909133046.136911C120F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79561:d69bcdeb2c61 Date: 2015-09-09 15:30 +0200 http://bitbucket.org/pypy/pypy/changeset/d69bcdeb2c61/ Log: be a bit more diligent what do we inherit in virtuals 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 @@ -20,6 +20,9 @@ def force_box(self, op, optforce): return op + def is_virtual(self): + return False + def is_precise(self): return False diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -39,6 +39,10 @@ i = infos.get(item, None) if i is not None: self.setinfo_from_preamble(item, i, infos) + else: + item.set_forwarded(None) + # let's not inherit stuff we don't + # know anything about def setinfo_from_preamble(self, op, preamble_info, exported_infos): op = self.get_box_replacement(op) @@ -128,10 +132,10 @@ def optimize_peeled_loop(self, start_label, end_jump, ops, state, call_pure_results, inline_short_preamble=True): self._check_no_forwarding([[start_label, end_jump], ops]) - try: - label_args = self.import_state(start_label, state) - except VirtualStatesCantMatch: - raise InvalidLoop("Cannot import state, virtual states don't match") + #try: + label_args = self.import_state(start_label, state) + #except VirtualStatesCantMatch: + # raise InvalidLoop("Cannot import state, virtual states don't match") self.potential_extra_ops = {} self.optimizer.init_inparg_dict_from(label_args) info, _ = self.optimizer.propagate_all_forward( @@ -349,6 +353,22 @@ for op in short: op.set_forwarded(None) + def _expand_info(self, arg, infos): + info = self.optimizer.getinfo(arg) + if arg in infos: + return + if info: + infos[arg] = info + if info.is_virtual(): + self._expand_infos_from_virtual(info, infos) + + def _expand_infos_from_virtual(self, info, infos): + items = info.all_items() + for item in items: + if item is None: + continue + self._expand_info(item, infos) + def export_state(self, start_label, original_label_args, renamed_inputargs, memo): end_args = [self.optimizer.force_box_for_end_of_preamble(a) @@ -358,11 +378,11 @@ end_args = [self.get_box_replacement(arg) for arg in end_args] infos = {} for arg in end_args: - infos[arg] = self.optimizer.getinfo(arg) + self._expand_info(arg, infos) label_args, virtuals = virtual_state.make_inputargs_and_virtuals( end_args, self.optimizer) for arg in label_args: - infos[arg] = self.optimizer.getinfo(arg) + self._expand_info(arg, infos) sb = ShortBoxes() short_boxes = sb.create_short_boxes(self.optimizer, renamed_inputargs, label_args + virtuals) From noreply at buildbot.pypy.org Thu Sep 10 09:08:19 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 10 Sep 2015 09:08:19 +0200 (CEST) Subject: [pypy-commit] pypy default: definitely a call we forgot Message-ID: <20150910070819.39AFA1C1342@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79578:65ea1299f0fe Date: 2015-09-10 09:08 +0200 http://bitbucket.org/pypy/pypy/changeset/65ea1299f0fe/ Log: definitely a call we forgot 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 @@ -406,7 +406,8 @@ optforce.emit_operation(setfield_op) def _visitor_walk_recursive(self, op, visitor, optimizer): - itemboxes = self._get_buffer().values + itemboxes = [optimizer.get_box_replacement(box) + for box in self._get_buffer().values] visitor.register_virtual_fields(op, itemboxes) # there can be no virtuals stored in raw buffer From noreply at buildbot.pypy.org Thu Sep 10 09:52:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 10 Sep 2015 09:52:00 +0200 (CEST) Subject: [pypy-commit] pypy default: a failing test Message-ID: <20150910075200.91ECE1C0325@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79579:6fe14ac7a5dd Date: 2015-09-10 09:52 +0200 http://bitbucket.org/pypy/pypy/changeset/6fe14ac7a5dd/ Log: a failing test 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 @@ -8803,5 +8803,30 @@ """ self.optimize_loop(ops, expected) + def test_resume_forced_raw_ptr(self): + ops = """ + [i0] + i = call_i('malloc', 10, descr=raw_malloc_descr) + is = int_add(i, 8) + escape_n(i) + i1 = int_add(i0, 1) + i2 = int_lt(i1, 100) + guard_true(i2) [is] + call_n('free', i, descr=raw_free_descr) + jump(i1) + """ + expected = """ + [i0] + i = call_i('malloc', 10, descr=raw_malloc_descr) + is = int_add(i, 8) + escape_n(i) + i1 = int_add(i0, 1) + i2 = int_lt(i1, 100) + guard_true(i2) [is] + call_n('free', i, descr=raw_free_descr) + jump(i1) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass From noreply at buildbot.pypy.org Thu Sep 10 09:59:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 10 Sep 2015 09:59:20 +0200 (CEST) Subject: [pypy-commit] pypy default: fix, really? is this it? Message-ID: <20150910075920.41B931C0325@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79580:5ca0a226a702 Date: 2015-09-10 09:59 +0200 http://bitbucket.org/pypy/pypy/changeset/5ca0a226a702/ Log: fix, really? is this it? 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 @@ -447,7 +447,8 @@ def _visitor_walk_recursive(self, op, visitor, optimizer): source_op = optimizer.get_box_replacement(op.getarg(0)) visitor.register_virtual_fields(op, [source_op]) - self.parent.visitor_walk_recursive(source_op, visitor, optimizer) + if self.parent.is_virtual(): + self.parent.visitor_walk_recursive(source_op, visitor, optimizer) @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): 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 @@ -8818,11 +8818,10 @@ expected = """ [i0] i = call_i('malloc', 10, descr=raw_malloc_descr) - is = int_add(i, 8) escape_n(i) i1 = int_add(i0, 1) i2 = int_lt(i1, 100) - guard_true(i2) [is] + guard_true(i2) [i] call_n('free', i, descr=raw_free_descr) jump(i1) """ From noreply at buildbot.pypy.org Thu Sep 10 11:51:32 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 10 Sep 2015 11:51:32 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: merged default Message-ID: <20150910095132.D73CD1C0325@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79581:3cf43a0720f1 Date: 2015-09-10 10:51 +0200 http://bitbucket.org/pypy/pypy/changeset/3cf43a0720f1/ Log: merged default diff too long, truncating to 2000 out of 12637 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -429,7 +430,7 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -303,7 +303,7 @@ RegrTest('test_memoryio.py'), RegrTest('test_memoryview.py'), RegrTest('test_md5.py'), - RegrTest('test_mhlib.py'), + RegrTest('test_mhlib.py', usemodules='binascii struct'), RegrTest('test_mimetools.py'), RegrTest('test_mimetypes.py'), RegrTest('test_MimeWriter.py', core=False, usemodules='binascii'), diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py --- a/lib_pypy/_curses.py +++ b/lib_pypy/_curses.py @@ -1026,16 +1026,22 @@ def tigetflag(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetflag(capname) def tigetnum(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetnum(capname) def tigetstr(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') val = lib.tigetstr(capname) if int(ffi.cast("intptr_t", val)) in (0, -1): return None diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.2.1 +Version: 1.3.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.2.1" -__version_info__ = (1, 2, 1) +__version__ = "1.3.0" +__version_info__ = (1, 3, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -214,6 +214,12 @@ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -648,10 +648,21 @@ assert typenames[-1] == '__dotdotdot__' if len(typenames) == 1: return model.unknown_type(decl.name) - for t in typenames[:-1]: - if t not in ['int', 'short', 'long', 'signed', 'unsigned', 'char']: - raise api.FFIError(':%d: bad usage of "..."' % decl.coord.line) + + if (typenames[:-1] == ['float'] or + typenames[:-1] == ['double']): + # not for 'long double' so far + result = model.UnknownFloatType(decl.name) + else: + for t in typenames[:-1]: + if t not in ['int', 'short', 'long', 'signed', + 'unsigned', 'char']: + raise api.FFIError(':%d: bad usage of "..."' % + decl.coord.line) + result = model.UnknownIntegerType(decl.name) + if self._uses_new_feature is None: self._uses_new_feature = "'typedef %s... %s'" % ( ' '.join(typenames[:-1]), decl.name) - return model.UnknownIntegerType(decl.name) + + return result diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -158,12 +158,23 @@ self.c_name_with_marker = name + '&' def is_integer_type(self): - return True # for now + return True def build_backend_type(self, ffi, finishlist): raise NotImplementedError("integer type '%s' can only be used after " "compilation" % self.name) +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + class BaseFunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -79,7 +79,9 @@ #define _CFFI_PRIM_UINTMAX 47 #define _CFFI__NUM_PRIM 48 -#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) struct _cffi_global_s { diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -468,6 +468,10 @@ if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), tp.name.replace(' ', '_')) @@ -522,6 +526,8 @@ if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type(): return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double': return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: @@ -1107,6 +1113,12 @@ ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -20,10 +20,6 @@ It initializes the RPython/PyPy GC and does a bunch of necessary startup code. This function cannot fail. -.. function:: void pypy_init_threads(void); - - Initialize threads. Only need to be called if there are any threads involved - .. function:: int pypy_setup_home(char* home, int verbose); This function searches the PyPy standard library starting from the given @@ -38,6 +34,11 @@ Function returns 0 on success or -1 on failure, can be called multiple times until the library is found. +.. function:: void pypy_init_threads(void); + + Initialize threads. Only need to be called if there are any threads involved. + *Must be called after pypy_setup_home()* + .. function:: int pypy_execute_source(char* source); Execute the Python source code given in the ``source`` argument. In case of diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 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 @@ -5,6 +5,23 @@ .. this is a revision shortly after release-2.6.1 .. startrev: 07769be4057b +.. branch: keys_with_hash +Improve the performance of dict.update() and a bunch of methods from +sets, by reusing the hash value stored in one dict when inspecting +or changing another dict with that key. + +.. branch: optresult-unroll +A major refactoring of the ResOperations that kills Box. Also rewrote +unrolling to enable future enhancements. Should improve warmup time +by 20% or so. + +.. branch: optimize-cond-call +Optimize common sequences of operations like +``int_lt/cond_call`` in the JIT backends + +.. branch: missing_openssl_include +Fix for missing headers in OpenBSD, already applied in downstream ports + .. branch: vecopt .. branch: vecopt-merge diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -111,22 +111,17 @@ 'interp_magic.mapdict_cache_counter') PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) - # XXX - # the following code prevents --fork-before=pyjitpl from working, - # proper fix would be to use some llop that is only rendered by the - # JIT - # - #try: - # from rpython.jit.backend import detect_cpu - # model = detect_cpu.autodetect() - # self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) - #except Exception: - # if self.space.config.translation.jit: - # raise - # else: - # pass # ok fine to ignore in this case - # - #if self.space.config.translation.jit: - ## features = detect_cpu.getcpufeatures(model) - # self.extra_interpdef('jit_backend_features', - # 'space.wrap(%r)' % features) + try: + from rpython.jit.backend import detect_cpu + model = detect_cpu.autodetect() + self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + except Exception: + if self.space.config.translation.jit: + raise + else: + pass # ok fine to ignore in this case + + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.2.1" +VERSION = "1.3.0" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -19,13 +19,27 @@ # ____________________________________________________________ +class Closure(object): + """This small class is here to have a __del__ outside any cycle.""" + + ll_error = lltype.nullptr(rffi.CCHARP.TO) # set manually + + def __init__(self, ptr): + self.ptr = ptr + + def __del__(self): + clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self.ptr)) + if self.ll_error: + lltype.free(self.ll_error, flavor='raw') + + class W_CDataCallback(W_CData): #_immutable_fields_ = ... - ll_error = lltype.nullptr(rffi.CCHARP.TO) w_onerror = None def __init__(self, space, ctype, w_callable, w_error, w_onerror): raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc()) + self._closure = Closure(raw_closure) W_CData.__init__(self, space, raw_closure, ctype) # if not space.is_true(space.callable(w_callable)): @@ -44,10 +58,11 @@ if size > 0: if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG: size = SIZE_OF_FFI_ARG - self.ll_error = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', - zero=True) + self._closure.ll_error = lltype.malloc(rffi.CCHARP.TO, size, + flavor='raw', zero=True) if not space.is_none(w_error): - convert_from_object_fficallback(fresult, self.ll_error, w_error) + convert_from_object_fficallback(fresult, self._closure.ll_error, + w_error) # self.unique_id = compute_unique_id(self) global_callback_mapping.set(self.unique_id, self) @@ -74,12 +89,6 @@ from pypy.module.thread.os_thread import setup_threads setup_threads(space) - #@rgc.must_be_light_finalizer - def __del__(self): - clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self._ptr)) - if self.ll_error: - lltype.free(self.ll_error, flavor='raw') - def _repr_extra(self): space = self.space return 'calling ' + space.str_w(space.repr(self.w_callable)) @@ -114,8 +123,8 @@ def write_error_return_value(self, ll_res): fresult = self.getfunctype().ctitem if fresult.size > 0: - misc._raw_memcopy(self.ll_error, ll_res, fresult.size) - keepalive_until_here(self) # to keep self.ll_error alive + misc._raw_memcopy(self._closure.ll_error, ll_res, fresult.size) + keepalive_until_here(self) # to keep self._closure.ll_error alive global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback) diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py --- a/pypy/module/_cffi_backend/cffi_opcode.py +++ b/pypy/module/_cffi_backend/cffi_opcode.py @@ -9,16 +9,16 @@ assert isinstance(self.arg, str) return '(_cffi_opcode_t)(%s)' % (self.arg,) classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg) + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) def as_python_bytes(self): - if self.op is None: - if self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): from .ffiplatform import VerificationError raise VerificationError("cannot emit to Python: %r" % (self.arg,)) return format_four_bytes((self.arg << 8) | self.op) @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -81,6 +81,13 @@ if num == cffi_opcode._UNKNOWN_PRIM: raise oefmt(ffi.w_FFIError, "primitive integer type with an " "unexpected size (or not an integer type at all)") + elif num == cffi_opcode._UNKNOWN_FLOAT_PRIM: + raise oefmt(ffi.w_FFIError, "primitive floating-point type with an " + "unexpected size (or not a float type at all)") + elif num == cffi_opcode._UNKNOWN_LONG_DOUBLE: + raise oefmt(ffi.w_FFIError, "primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") else: raise oefmt(space.w_NotImplementedError, "prim=%d", num) realize_cache = space.fromcache(RealizeCache) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,6 +1,9 @@ # ____________________________________________________________ import sys +assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" + " of cffi that differs from the one that we" + " get from 'import _cffi_backend'") if sys.version_info < (3,): type_or_class = "type" mandatory_b_prefix = '' @@ -3424,7 +3427,3 @@ "be 'foo *', but the types are different (check " "that you are not e.g. mixing up different ffi " "instances)") - -def test_version(): - # this test is here mostly for PyPy - assert __version__ == "1.2.1" diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -326,7 +326,7 @@ # to repeat it every time ticker_check = """ guard_not_invalidated? - ticker0 = getfield_raw(#, descr=) + ticker0 = getfield_raw_i(#, descr=) ticker_cond0 = int_lt(ticker0, 0) guard_false(ticker_cond0, descr=...) """ @@ -335,7 +335,7 @@ # this is the ticker check generated if we have threads thread_ticker_check = """ guard_not_invalidated? - ticker0 = getfield_raw(#, descr=) + ticker0 = getfield_raw_i(#, descr=) ticker1 = int_sub(ticker0, #) setfield_raw(#, ticker1, descr=) ticker_cond0 = int_lt(ticker1, 0) @@ -345,7 +345,7 @@ # # this is the ticker check generated in PyFrame.handle_operation_error exc_ticker_check = """ - ticker2 = getfield_raw(#, descr=) + ticker2 = getfield_raw_i(#, descr=) ticker_cond1 = int_lt(ticker2, 0) guard_false(ticker_cond1, descr=...) """ diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -76,7 +76,7 @@ stdout = stdout.splitlines(True)[-1] # # parse the JIT log - rawlog = logparser.parse_log_file(str(logfile)) + rawlog = logparser.parse_log_file(str(logfile), verbose=False) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) @@ -471,7 +471,7 @@ # this is the actual loop 'int_lt', 'guard_true', 'int_add', # this is the signal checking stuff - 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false', + 'guard_not_invalidated', 'getfield_raw_i', 'int_lt', 'guard_false', 'jump' ] @@ -536,7 +536,7 @@ # this is the actual loop 'int_lt', 'guard_true', 'force_token', 'int_add', # this is the signal checking stuff - 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false', + 'guard_not_invalidated', 'getfield_raw_i', 'int_lt', 'guard_false', 'jump' ] @@ -555,7 +555,7 @@ i8 = int_add(i4, 1) # signal checking stuff guard_not_invalidated(descr=...) - i10 = getfield_raw(..., descr=<.* pypysig_long_struct.c_value .*>) + i10 = getfield_raw_i(..., descr=<.* pypysig_long_struct.c_value .*>) i14 = int_lt(i10, 0) guard_false(i14, descr=...) jump(..., descr=...) @@ -609,13 +609,13 @@ log = self.run(f, import_site=True) loop, = log.loops_by_id('ntohs') assert loop.match_by_id('ntohs', """ - p12 = call(ConstClass(ntohs), 1, descr=...) + i12 = call_i(ConstClass(ntohs), 1, descr=...) guard_no_exception(descr=...) """, include_guard_not_invalidated=False) # py.test.raises(InvalidMatch, loop.match_by_id, 'ntohs', """ guard_not_invalidated(descr=...) - p12 = call(ConstClass(foobar), 1, descr=...) + i12 = call_i(ConstClass(foobar), 1, descr=...) guard_no_exception(descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -42,7 +42,7 @@ guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) - i15 = getarrayitem_raw(i10, i7, descr=) + i15 = getarrayitem_raw_i(i10, i7, descr=) i16 = int_add_ovf(i8, i15) guard_no_overflow(descr=...) i18 = int_add(i7, 1) @@ -74,12 +74,12 @@ guard_true(i13, descr=...) guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=) + i14 = getarrayitem_raw_i(i10, i8, descr=) i15 = int_add_ovf(i9, i14) guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=) + i18 = getarrayitem_raw_i(i11, i17, descr=) i19 = int_add_ovf(i18, i15) guard_no_overflow(descr=...) setarrayitem_raw(i11, i8, _, descr=) @@ -93,7 +93,7 @@ guard_true(i13, descr=...) guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=) + i14 = getarrayitem_raw_i(i10, i8, descr=) # advanced: the following int_add cannot overflow, because: # - i14 fits inside 32 bits # - i9 fits inside 33 bits, because: @@ -107,7 +107,7 @@ i15 = int_add(i9, i14) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=) + i18 = getarrayitem_raw_i(i11, i17, descr=) i19 = int_add(i18, i15) # guard checking that i19 actually fits into 32bit i20 = int_signext(i19, 4) @@ -139,10 +139,10 @@ guard_true(i10, descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) - f13 = getarrayitem_raw(i8, i6, descr=) + f13 = getarrayitem_raw_f(i8, i6, descr=) f15 = float_add(f13, 20.500000) setarrayitem_raw(i8, i6, f15, descr=) - f16 = getarrayitem_raw(i8, i6, descr=) + f16 = getarrayitem_raw_f(i8, i6, descr=) i18 = float_eq(f16, 42.000000) guard_true(i18, descr=...) i20 = int_add(i6, 1) @@ -175,12 +175,12 @@ guard_true(i10, descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) - i13 = getarrayitem_raw(i8, i6, descr=) + i13 = getarrayitem_raw_i(i8, i6, descr=) f14 = cast_singlefloat_to_float(i13) f16 = float_add(f14, 20.500000) i17 = cast_float_to_singlefloat(f16) setarrayitem_raw(i8, i6,i17, descr=) - i18 = getarrayitem_raw(i8, i6, descr=) + i18 = getarrayitem_raw_i(i8, i6, descr=) f19 = cast_singlefloat_to_float(i18) i21 = float_eq(f19, 42.000000) guard_true(i21, descr=...) @@ -225,23 +225,23 @@ ... i20 = int_ge(i18, i8) guard_false(i20, descr=...) - f21 = getarrayitem_raw(i13, i18, descr=...) + f21 = getarrayitem_raw_f(i13, i18, descr=...) i14 = int_sub(i6, 1) i15 = int_ge(i14, i8) guard_false(i15, descr=...) - f23 = getarrayitem_raw(i13, i14, descr=...) + f23 = getarrayitem_raw_f(i13, i14, descr=...) f24 = float_add(f21, f23) - f26 = getarrayitem_raw(i13, i6, descr=...) + f26 = getarrayitem_raw_f(i13, i6, descr=...) f27 = float_add(f24, f26) i29 = int_add(i6, 1) i31 = int_ge(i29, i8) guard_false(i31, descr=...) - f33 = getarrayitem_raw(i13, i29, descr=...) + f33 = getarrayitem_raw_f(i13, i29, descr=...) f34 = float_add(f27, f33) i36 = int_add(i6, 2) i38 = int_ge(i36, i8) guard_false(i38, descr=...) - f39 = getarrayitem_raw(i13, i36, descr=...) + f39 = getarrayitem_raw_f(i13, i36, descr=...) ... """) @@ -276,20 +276,20 @@ expected_src=""" ... i17 = int_and(i14, 255) - f18 = getarrayitem_raw(i8, i17, descr=...) + f18 = getarrayitem_raw_f(i8, i17, descr=...) i19s = int_sub_ovf(i6, 1) guard_no_overflow(descr=...) i22s = int_and(i19s, 255) - f20 = getarrayitem_raw(i8, i22s, descr=...) + f20 = getarrayitem_raw_f(i8, i22s, descr=...) f21 = float_add(f18, f20) - f23 = getarrayitem_raw(i8, i10, descr=...) + f23 = getarrayitem_raw_f(i8, i10, descr=...) f24 = float_add(f21, f23) i26 = int_add(i6, 1) i29 = int_and(i26, 255) - f30 = getarrayitem_raw(i8, i29, descr=...) + f30 = getarrayitem_raw_f(i8, i29, descr=...) f31 = float_add(f24, f30) i33 = int_add(i6, 2) i36 = int_and(i33, 255) - f37 = getarrayitem_raw(i8, i36, descr=...) + f37 = getarrayitem_raw_f(i8, i36, descr=...) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_buffers.py b/pypy/module/pypyjit/test_pypy_c/test_buffers.py --- a/pypy/module/pypyjit/test_pypy_c/test_buffers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_buffers.py @@ -18,7 +18,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('match', """ guard_not_invalidated(descr=...) - i65 = getfield_gc(p18, descr=...) + i65 = getfield_gc_i(p18, descr=...) i67 = int_gt(0, i65) guard_false(i67, descr=...) i69 = int_gt(#, i65) @@ -42,7 +42,7 @@ assert loop.match_by_id('unpack', """ guard_not_invalidated(descr=...) p90 = newstr(4) - call(ConstClass(copy_raw_to_string), i55, p90, 0, 4, descr=) + call_n(ConstClass(copy_raw_to_string), i55, p90, 0, 4, descr=) guard_no_exception(descr=...) i91 = strgetitem(p90, 0) i92 = strgetitem(p90, 1) @@ -56,7 +56,7 @@ guard_false(i99, descr=...) i100 = int_lshift(i98, 24) i101 = int_or(i97, i100) - i102 = getfield_raw(#, descr=) + i102 = getfield_raw_i(#, descr=) i103 = int_lt(i102, 0) guard_false(i103, descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -31,7 +31,7 @@ functrace, loop = log.loops_by_filename(self.filepath) assert loop.match_by_id('call_rec', """ ... - p53 = call_assembler(..., descr=...) + p53 = call_assembler_r(..., descr=...) guard_not_forced(descr=...) keepalive(...) guard_no_exception(descr=...) @@ -73,7 +73,7 @@ ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", "guard_value", - "getfield_gc", "guard_value", + "getfield_gc_r", "guard_value", "guard_not_invalidated"] ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') assert log.opnames(ops) == [] @@ -82,12 +82,12 @@ assert log.opnames(ops) == [] # assert entry_bridge.match_by_id('call', """ - p38 = call(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) - p39 = getfield_gc(p38, descr=) + p38 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) + p39 = getfield_gc_r(p38, descr=) i40 = force_token() - p41 = getfield_gc_pure(p38, descr=) + p41 = getfield_gc_pure_r(p38, descr=) guard_value(p41, ConstPtr(ptr42), descr=...) - i42 = getfield_gc_pure(p38, descr=) + i42 = getfield_gc_pure_i(p38, descr=) i43 = int_is_zero(i42) guard_true(i43, descr=...) i50 = force_token() @@ -130,7 +130,8 @@ # ------------------------------- entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + assert log.opnames(ops) == ['guard_value', 'getfield_gc_r', + 'guard_value', 'guard_not_invalidated'] # the second LOOKUP_METHOD is folded away assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] @@ -349,15 +350,13 @@ # the int strategy is used here assert loop.match_by_id('append', """ guard_not_invalidated? - i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) - p15 = getfield_gc(p8, descr=) i17 = arraylen_gc(p15, descr=) i18 = int_lt(i17, i15) # a cond call to _ll_list_resize_hint_really_look_inside_iff cond_call(i18, _, p8, i15, 1, descr=) guard_no_exception(descr=...) - p17 = getfield_gc(p8, descr=) + p17 = getfield_gc_r(p8, descr=) setarrayitem_gc(p17, i13, i12, descr=) """) @@ -381,9 +380,9 @@ # make sure that the "block" is not allocated ... p20 = force_token() - p22 = new_with_vtable(...) + p22 = new_with_vtable(descr=) p24 = new_array_clear(1, descr=) - p26 = new_with_vtable(ConstClass(W_ListObject)) + p26 = new_with_vtable(descr=) {{{ setfield_gc(p0, p20, descr=) setfield_gc(p22, ConstPtr(null), descr=) @@ -395,7 +394,7 @@ setarrayitem_gc(p24, 0, p26, descr=) setfield_gc(p22, p24, descr=) }}} - p32 = call_may_force(_, p18, p22, descr=) + p32 = call_may_force_r(_, p18, p22, descr=) ... """) @@ -436,24 +435,24 @@ guard_isnull(p5, descr=...) guard_nonnull_class(p12, ConstClass(W_IntObject), descr=...) guard_value(p2, ConstPtr(ptr21), descr=...) - i22 = getfield_gc_pure(p12, descr=) + i22 = getfield_gc_pure_i(p12, descr=) i24 = int_lt(i22, 5000) guard_true(i24, descr=...) guard_value(p7, ConstPtr(ptr25), descr=...) - p26 = getfield_gc(p7, descr=) + p26 = getfield_gc_r(p7, descr=) guard_value(p26, ConstPtr(ptr27), descr=...) guard_not_invalidated(descr=...) - p29 = call(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) - p30 = getfield_gc(p29, descr=) + p29 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) + p30 = getfield_gc_r(p29, descr=) p31 = force_token() - p32 = getfield_gc_pure(p29, descr=) + p32 = getfield_gc_pure_r(p29, descr=) guard_value(p32, ConstPtr(ptr33), descr=...) - i34 = getfield_gc_pure(p29, descr=) + i34 = getfield_gc_pure_i(p29, descr=) i35 = int_is_zero(i34) guard_true(i35, descr=...) - p37 = getfield_gc(ConstPtr(ptr36), descr=) + p37 = getfield_gc_r(ConstPtr(ptr36), descr=) guard_nonnull_class(p37, ConstClass(W_IntObject), descr=...) - i39 = getfield_gc_pure(p37, descr=) + i39 = getfield_gc_pure_i(p37, descr=) i40 = int_add_ovf(i22, i39) guard_no_overflow(descr=...) --TICK-- @@ -470,13 +469,13 @@ """, []) loop, = log.loops_by_id('call') assert loop.match(""" - i8 = getfield_gc_pure(p6, descr=) + i8 = getfield_gc_pure_i(p6, descr=) i10 = int_lt(i8, 5000) guard_true(i10, descr=...) i11 = force_token() i13 = int_add(i8, 1) --TICK-- - p22 = new_with_vtable(ConstClass(W_IntObject)) + p22 = new_with_vtable(descr=) setfield_gc(p22, i13, descr=) setfield_gc(p4, p22, descr=) jump(..., descr=...) @@ -576,8 +575,8 @@ allops = loop.allops() calls = [op for op in allops if op.name.startswith('call')] assert OpMatcher(calls).match(''' - p93 = call(ConstClass(view_as_kwargs), p35, p12, descr=<.*>) - i103 = call(ConstClass(_match_keywords), ConstPtr(ptr52), 0, 0, p94, p98, 0, descr=<.*>) + p93 = call_r(ConstClass(view_as_kwargs), p35, p12, descr=<.*>) + i103 = call_i(ConstClass(_match_keywords), ConstPtr(ptr52), 0, 0, p94, p98, 0, descr=<.*>) ''') assert len([op for op in allops if op.name.startswith('new')]) == 1 # 1 alloc diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -163,7 +163,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('getfield', """ guard_not_invalidated(descr=...) - i57 = getfield_raw(i46, descr=) + i57 = getfield_raw_i(i46, descr=) """) assert loop.match_by_id('setfield', """ setfield_raw(i44, i57, descr=) @@ -202,7 +202,7 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - f97 = call_release_gil(91, i59, 1.0, 3, descr=) + f97 = call_release_gil_f(91, i59, 1.0, 3, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) """, ignore_ops=['guard_not_invalidated']) @@ -244,7 +244,7 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - i97 = call_release_gil(91, i59, i50, descr=) + i97 = call_release_gil_i(91, i59, i50, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) %s @@ -288,10 +288,10 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - i97 = call_release_gil(91, i59, i10, i12, 1, descr=) + i97 = call_release_gil_i(91, i59, i10, i12, 1, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) - p98 = call(ConstClass(fromrarith_int__r_uint), i97, descr=) + p98 = call_r(ConstClass(fromrarith_int__r_uint), i97, descr=) guard_no_exception(descr=...) """, ignore_ops=['guard_not_invalidated']) @@ -354,7 +354,7 @@ loop, = log.loops_by_id('cfficall') assert loop.match_by_id('cfficall', """ ... - f1 = call_release_gil(..., descr=) + i1 = call_release_gil_i(..., descr=) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -120,7 +120,7 @@ i59 = int_add_ovf(i57, 1) guard_no_overflow(descr=...) p60 = force_token() - i61 = getfield_raw(..., descr=...) + i61 = getfield_raw_i(..., descr=...) setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) @@ -172,7 +172,7 @@ p72 = force_token() p73 = force_token() i74 = int_add(i58, 1) - i75 = getfield_raw(..., descr=...) + i75 = getfield_raw_i(..., descr=...) i76 = int_lt(i75, 0) guard_false(i76, descr=...) p77 = new_with_vtable(...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -266,7 +266,7 @@ i91 = int_add(i87, 1) i93 = int_add(i89, 8) i94 = int_add(i79, 1) - i95 = getfield_raw(#, descr=) + i95 = getfield_raw_i(#, descr=) setfield_gc(p97, i91, descr=) setfield_gc(p97, i93, descr=) i96 = int_lt(i95, 0) @@ -326,7 +326,7 @@ guard_not_invalidated(descr=...) raw_store(i103, i132, 42.000000, descr=) i153 = int_add(i120, 1) - i154 = getfield_raw(#, descr=) + i154 = getfield_raw_i(#, descr=) setarrayitem_gc(p152, 1, 0, descr=) setarrayitem_gc(p152, 0, 0, descr=) setfield_gc(p158, i53, descr=) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1,7 +1,7 @@ # Generated by pypy/tool/import_cffi.py import sys, os, py -from cffi import FFI, VerificationError +from cffi import FFI, VerificationError, FFIError from cffi import recompiler from pypy.module.test_lib_pypy.cffi_tests.udir import udir from pypy.module.test_lib_pypy.cffi_tests.support import u @@ -1057,14 +1057,54 @@ assert lib.nu == 20 def test_some_float_type(): - py.test.skip("later") ffi = FFI() - ffi.cdef("typedef double... foo_t; foo_t sum(foo_t[]);") + ffi.cdef(""" + typedef double... foo_t; + typedef float... bar_t; + foo_t sum(foo_t[]); + bar_t neg(bar_t); + """) lib = verify(ffi, 'test_some_float_type', """ typedef float foo_t; static foo_t sum(foo_t x[]) { return x[0] + x[1]; } + typedef double bar_t; + static double neg(double x) { return -x; } """) assert lib.sum([40.0, 2.25]) == 42.25 + assert lib.sum([12.3, 45.6]) != 12.3 + 45.6 # precision loss + assert lib.neg(12.3) == -12.3 # no precision loss + assert ffi.sizeof("foo_t") == ffi.sizeof("float") + assert ffi.sizeof("bar_t") == ffi.sizeof("double") + +def test_some_float_invalid_1(): + ffi = FFI() + py.test.raises(FFIError, ffi.cdef, "typedef long double... foo_t;") + +def test_some_float_invalid_2(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_2', """ + typedef unsigned long foo_t; + foo_t neg(foo_t x) { return -x; } + """) + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type with an unexpected " + "size (or not a float type at all)") + +def test_some_float_invalid_3(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_3', """ + typedef long double foo_t; + foo_t neg(foo_t x) { return -x; } + """) + if ffi.sizeof("long double") == ffi.sizeof("double"): + assert lib.neg(12.3) == -12.3 + else: + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") def test_issue200(): ffi = FFI() diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,12 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): @@ -989,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1020,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1105,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1125,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1152,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -520,26 +520,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -4492,6 +4492,15 @@ with py.test.raises(annmodel.AnnotatorError): a.build_types(f, [int]) + def test_dict_can_be_none_ordering_issue(self): + def g(d): + return 42 in d + def f(n): + g(None) + g({}) + a = self.RPythonAnnotator() + a.build_types(f, [int]) + def g(n): return [0, 1, 2, n] diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -11,11 +12,13 @@ SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue, - s_Bool, s_None, unionof, add_knowntypedata, + s_Bool, s_None, s_Int, unionof, add_knowntypedata, HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray) from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -46,6 +49,16 @@ return s_Bool contains_SomeObject.can_only_throw = [] + at op.contains.register(SomeNone) +def contains_SomeNone(annotator, obj, element): + # return False here for the case "... in None", because it can be later + # generalized to "... in d" where d is either None or the empty dict + # (which would also return the constant False) + s_bool = SomeBool() + s_bool.const = False + return s_bool +contains_SomeNone.can_only_throw = [] + @op.simple_call.register(SomeObject) def simple_call_SomeObject(annotator, func, *args): return annotator.annotation(func).call( @@ -364,20 +377,19 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - at op.contains.register(SomeDict) -def contains_SomeDict(annotator, dct, element): - annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) - if annotator.annotation(dct)._is_empty(): +def dict_contains(s_dct, s_element): + s_dct.dictdef.generalize_key(s_element) + if s_dct._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool -contains_SomeDict.can_only_throw = _can_only_throw + + at op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + return dict_contains(annotator.annotation(dct), + annotator.annotation(element)) +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -401,16 +413,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -448,6 +466,12 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass @@ -460,6 +484,22 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/doc/conf.py b/rpython/doc/conf.py --- a/rpython/doc/conf.py +++ b/rpython/doc/conf.py @@ -68,7 +68,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -12,8 +12,7 @@ from rpython.jit.backend.arm.opassembler import ResOpAssembler from rpython.jit.backend.arm.regalloc import (Regalloc, CoreRegisterManager, check_imm_arg, VFPRegisterManager, - operations as regalloc_operations, - operations_with_guard as regalloc_operations_with_guard) + operations as regalloc_operations) from rpython.jit.backend.llsupport import jitframe, rewrite from rpython.jit.backend.llsupport.assembler import DEBUG_COUNTER, debug_bridge, BaseAssembler from rpython.jit.backend.llsupport.regalloc import get_scale, valid_addressing_size @@ -645,8 +644,10 @@ size_excluding_failure_stuff - loop_head) def _assemble(self, regalloc, inputargs, operations): + self.guard_success_cc = c.cond_none regalloc.compute_hint_frame_locations(operations) self._walk_operations(inputargs, operations, regalloc) + assert self.guard_success_cc == c.cond_none frame_depth = regalloc.get_final_frame_depth() jump_target_descr = regalloc.jump_target_descr if jump_target_descr is not None: @@ -707,7 +708,7 @@ self.fixup_target_tokens(rawstart) self.update_frame_depth(frame_depth) if logger: - logger.log_bridge(inputargs, operations, "rewritten", + logger.log_bridge(inputargs, operations, "rewritten", faildescr, ops_offset=ops_offset) self.teardown() @@ -927,6 +928,7 @@ def _walk_operations(self, inputargs, operations, regalloc): fcond = c.AL self._regalloc = regalloc + regalloc.operations = operations while regalloc.position() < len(operations) - 1: regalloc.next_instruction() i = regalloc.position() @@ -934,20 +936,9 @@ op = operations[i] self.mc.mark_op(op) opnum = op.getopnum() - if op.has_no_side_effect() and op.result not in regalloc.longevity: + if op.has_no_side_effect() and op not in regalloc.longevity: regalloc.possibly_free_vars_for_op(op) - elif self._regalloc.can_merge_with_next_guard(op, i, operations): - guard = operations[i + 1] - assert guard.is_guard() - arglocs = regalloc_operations_with_guard[opnum](regalloc, op, - guard, fcond) - fcond = asm_operations_with_guard[opnum](self, op, - guard, arglocs, regalloc, fcond) - assert fcond is not None - regalloc.next_instruction() - regalloc.possibly_free_vars_for_op(guard) - regalloc.possibly_free_vars(guard.getfailargs()) - elif not we_are_translated() and op.getopnum() == -124: + elif not we_are_translated() and op.getopnum() == -127: regalloc.prepare_force_spill(op, fcond) else: arglocs = regalloc_operations[opnum](regalloc, op, fcond) @@ -957,12 +948,13 @@ assert fcond is not None if op.is_guard(): regalloc.possibly_free_vars(op.getfailargs()) - if op.result: - regalloc.possibly_free_var(op.result) + if op.type != 'v': + regalloc.possibly_free_var(op) regalloc.possibly_free_vars_for_op(op) regalloc.free_temp_vars() regalloc._check_invariants() self.mc.mark_op(None) # end of the loop + regalloc.operations = None def regalloc_emit_extra(self, op, arglocs, fcond, regalloc): # for calls to a function with a specifically-supported OS_xxx @@ -1517,21 +1509,11 @@ raise NotImplementedError(op) -def notimplemented_op_with_guard(self, op, guard_op, arglocs, regalloc, fcond): - print "[ARM/asm] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - asm_operations = [notimplemented_op] * (rop._LAST + 1) -asm_operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) asm_extra_operations = {} for name, value in ResOpAssembler.__dict__.iteritems(): - if name.startswith('emit_guard_'): - opname = name[len('emit_guard_'):] - num = getattr(rop, opname.upper()) - asm_operations_with_guard[num] = value - elif name.startswith('emit_opx_'): + if name.startswith('emit_opx_'): opname = name[len('emit_opx_'):] num = getattr(EffectInfo, 'OS_' + opname.upper()) asm_extra_operations[num] = value diff --git a/rpython/jit/backend/arm/conditions.py b/rpython/jit/backend/arm/conditions.py --- a/rpython/jit/backend/arm/conditions.py +++ b/rpython/jit/backend/arm/conditions.py @@ -13,11 +13,13 @@ GT = 0xC LE = 0xD AL = 0xE +cond_none = -1 opposites = [NE, EQ, CC, CS, PL, MI, VC, VS, LS, HI, LT, GE, LE, GT, AL] def get_opposite_of(operation): + assert operation >= 0 return opposites[operation] # see mapping for floating poin according to diff --git a/rpython/jit/backend/arm/helper/assembler.py b/rpython/jit/backend/arm/helper/assembler.py --- a/rpython/jit/backend/arm/helper/assembler.py +++ b/rpython/jit/backend/arm/helper/assembler.py @@ -2,37 +2,36 @@ from rpython.jit.backend.arm import conditions as c from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.codebuilder import InstrBuilder -from rpython.jit.metainterp.history import ConstInt, BoxInt, FLOAT +from rpython.jit.metainterp.history import FLOAT from rpython.rlib.rarithmetic import r_uint, r_longlong, intmask from rpython.jit.metainterp.resoperation import rop + +def flush_cc(asm, condition, result_loc): + # After emitting an instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to 'fp' by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert asm.guard_success_cc == c.cond_none + if result_loc is r.fp: + asm.guard_success_cc = condition + else: + asm.mc.MOV_ri(result_loc.value, 1, condition) + asm.mc.MOV_ri(result_loc.value, 0, c.get_opposite_of(condition)) + + def gen_emit_op_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None reg, res = arglocs self.mc.CMP_ri(reg.value, 0) - self.mc.MOV_ri(res.value, 1, true_cond) - self.mc.MOV_ri(res.value, 0, false_cond) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_guard_unary_cmp(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert fcond is not None - assert guard is not None - reg = arglocs[0] - self.mc.CMP_ri(reg.value, 0) - cond = true_cond - guard_opnum = guard.getopnum() - if guard_opnum == rop.GUARD_FALSE: - cond = false_cond - return self._emit_guard(guard, arglocs[1:], cond, save_exc=False) - f.__name__ = 'emit_guard_%s' % name - return f - def gen_emit_op_ri(name, opname): ri_op = getattr(InstrBuilder, '%s_ri' % opname) rr_op = getattr(InstrBuilder, '%s_rr' % opname) @@ -51,7 +50,7 @@ helper = getattr(InstrBuilder, opname) def f(self, op, arglocs, regalloc, fcond): assert fcond is not None - if op.result: + if op.type != 'v': regs = r.caller_resp[1:] + [r.ip] else: regs = r.caller_resp @@ -61,8 +60,7 @@ f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op(name, condition): - inv = c.get_opposite_of(condition) +def gen_emit_cmp_op(name, true_cond): def f(self, op, arglocs, regalloc, fcond): l0, l1, res = arglocs @@ -70,32 +68,11 @@ self.mc.CMP_ri(l0.value, imm=l1.getint(), cond=fcond) else: self.mc.CMP_rr(l0.value, l1.value, cond=fcond) - self.mc.MOV_ri(res.value, 1, cond=condition) - self.mc.MOV_ri(res.value, 0, cond=inv) + flush_cc(self, true_cond, res) return fcond f.__name__ = 'emit_op_%s' % name return f -def gen_emit_cmp_op_guard(name, true_cond): - false_cond = c.get_opposite_of(true_cond) - def f(self, op, guard, arglocs, regalloc, fcond): - assert guard is not None From noreply at buildbot.pypy.org Thu Sep 10 11:51:35 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 10 Sep 2015 11:51:35 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: syntax error from merging and wrong indentation, Message-ID: <20150910095135.4DA011C0325@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79582:bd74760268d5 Date: 2015-09-10 11:51 +0200 http://bitbucket.org/pypy/pypy/changeset/bd74760268d5/ Log: syntax error from merging and wrong indentation, started to revive the dependency construction 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 @@ -1274,56 +1274,56 @@ def _new_execute_call_assembler(def_val): def _execute_call_assembler(self, descr, *args): - # XXX simplify the following a bit - # - # pframe = CALL_ASSEMBLER(args..., descr=looptoken) - # ==> - # pframe = CALL looptoken.loopaddr(*args) - # JUMP_IF_FAST_PATH @fastpath - # res = CALL assembler_call_helper(pframe) - # jmp @done - # @fastpath: - # res = GETFIELD(pframe, 'result') - # @done: - # - call_op = self.lltrace.operations[self.current_index] - guard_op = self.lltrace.operations[self.current_index + 1] - assert guard_op.getopnum() == rop.GUARD_NOT_FORCED - self.force_guard_op = guard_op - pframe = self.cpu._execute_token(descr, *args) - del self.force_guard_op - # - jd = descr.outermost_jitdriver_sd - assert jd is not None, ("call_assembler(): the loop_token needs " - "to have 'outermost_jitdriver_sd'") - if jd.index_of_virtualizable != -1: - vable = args[jd.index_of_virtualizable] - else: - vable = lltype.nullptr(llmemory.GCREF.TO) - # - # Emulate the fast path - # - faildescr = self.cpu.get_latest_descr(pframe) - if faildescr == self.cpu.done_with_this_frame_descr_int: - return self.cpu.get_int_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_ref: - return self.cpu.get_ref_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_float: - return self.cpu.get_float_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_void: - return None + # XXX simplify the following a bit + # + # pframe = CALL_ASSEMBLER(args..., descr=looptoken) + # ==> + # pframe = CALL looptoken.loopaddr(*args) + # JUMP_IF_FAST_PATH @fastpath + # res = CALL assembler_call_helper(pframe) + # jmp @done + # @fastpath: + # res = GETFIELD(pframe, 'result') + # @done: + # + call_op = self.lltrace.operations[self.current_index] + guard_op = self.lltrace.operations[self.current_index + 1] + assert guard_op.getopnum() == rop.GUARD_NOT_FORCED + self.force_guard_op = guard_op + pframe = self.cpu._execute_token(descr, *args) + del self.force_guard_op + # + jd = descr.outermost_jitdriver_sd + assert jd is not None, ("call_assembler(): the loop_token needs " + "to have 'outermost_jitdriver_sd'") + if jd.index_of_virtualizable != -1: + vable = args[jd.index_of_virtualizable] + else: + vable = lltype.nullptr(llmemory.GCREF.TO) + # + # Emulate the fast path + # + faildescr = self.cpu.get_latest_descr(pframe) + if faildescr == self.cpu.done_with_this_frame_descr_int: + return self.cpu.get_int_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_ref: + return self.cpu.get_ref_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_float: + return self.cpu.get_float_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_void: + return None - assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish - try: - result = assembler_helper_ptr(pframe, vable) - except LLException, lle: - assert self.last_exception is None, "exception left behind" - self.last_exception = lle - # fish op + assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish + try: + result = assembler_helper_ptr(pframe, vable) + except LLException, lle: + assert self.last_exception is None, "exception left behind" + self.last_exception = lle + # fish op result = def_val - if isinstance(result, float): - result = support.cast_to_floatstorage(result) - return result + if isinstance(result, float): + result = support.cast_to_floatstorage(result) + return result return _execute_call_assembler execute_call_assembler_i = _new_execute_call_assembler(0) diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -17,37 +17,37 @@ @specialize.arg(4) def _do_call(cpu, metainterp, argboxes, descr, rettype): - assert metainterp is not None - # count the number of arguments of the different types - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - type = argboxes[i].type - if type == INT: count_i += 1 - elif type == REF: count_r += 1 - elif type == FLOAT: count_f += 1 - # allocate lists for each type that has at least one argument - if count_i: args_i = [0] * count_i - else: args_i = None - if count_r: args_r = [NULL] * count_r - else: args_r = None - if count_f: args_f = [longlong.ZEROF] * count_f - else: args_f = None - # fill in the lists - count_i = count_r = count_f = 0 - for i in range(1, len(argboxes)): - box = argboxes[i] - if box.type == INT: - args_i[count_i] = box.getint() - count_i += 1 - elif box.type == REF: - args_r[count_r] = box.getref_base() - count_r += 1 - elif box.type == FLOAT: - args_f[count_f] = box.getfloatstorage() - count_f += 1 - # get the function address as an integer - func = argboxes[0].getint() - # do the call using the correct function from the cpu + assert metainterp is not None + # count the number of arguments of the different types + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + type = argboxes[i].type + if type == INT: count_i += 1 + elif type == REF: count_r += 1 + elif type == FLOAT: count_f += 1 + # allocate lists for each type that has at least one argument + if count_i: args_i = [0] * count_i + else: args_i = None + if count_r: args_r = [NULL] * count_r + else: args_r = None + if count_f: args_f = [longlong.ZEROF] * count_f + else: args_f = None + # fill in the lists + count_i = count_r = count_f = 0 + for i in range(1, len(argboxes)): + box = argboxes[i] + if box.type == INT: + args_i[count_i] = box.getint() + count_i += 1 + elif box.type == REF: + args_r[count_r] = box.getref_base() + count_r += 1 + elif box.type == FLOAT: + args_f[count_f] = box.getfloatstorage() + count_f += 1 + # get the function address as an integer + func = argboxes[0].getint() + # do the call using the correct function from the cpu if rettype == INT: try: result = cpu.bh_call_i(func, args_i, args_r, args_f, descr) @@ -386,11 +386,14 @@ rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME, rop.NURSERY_PTR_INCREMENT, rop.LABEL, - rop.VEC_RAW_LOAD, + rop.VEC_RAW_LOAD_I, + rop.VEC_RAW_LOAD_F, rop.VEC_RAW_STORE, - rop.VEC_GETARRAYITEM_RAW, + rop.VEC_GETARRAYITEM_RAW_I, + rop.VEC_GETARRAYITEM_RAW_F, rop.VEC_SETARRAYITEM_RAW, - rop.VEC_GETARRAYITEM_GC, + rop.VEC_GETARRAYITEM_GC_I, + rop.VEC_GETARRAYITEM_GC_F, rop.VEC_SETARRAYITEM_GC, ): # list of opcodes never executed by pyjitpl continue diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -369,92 +369,6 @@ # ____________________________________________________________ -class Accum(object): - PLUS = '+' - MULTIPLY = '*' - - def __init__(self, opnum, var, pos): - self.var = var - self.pos = pos - self.operator = Accum.PLUS - if opnum == rop.FLOAT_MUL: - self.operator = Accum.MULTIPLY - - def getoriginalbox(self): - return self.var - - def getop(self): - return self.operator - - def accumulates_value(self): - return True - -class BoxVector(Box): - type = VECTOR - _attrs_ = ('item_type','item_count','item_size','item_signed','accum') - _extended_display = False - - def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): - assert item_type in (FLOAT, INT) - self.item_type = item_type - self.item_count = item_count - self.item_size = item_size - self.item_signed = item_signed - self.accum = None - - def gettype(self): - return self.item_type - - def getsize(self): - return self.item_size - - def getsigned(self): - return self.item_signed - - def getcount(self): - return self.item_count - - def fully_packed(self, vec_reg_size): - return self.item_size * self.item_count == vec_reg_size - - def forget_value(self): - raise NotImplementedError("cannot forget value of vector") - - def clonebox(self): - return BoxVector(self.item_type, self.item_count, self.item_size, self.item_signed) - - def constbox(self): - raise NotImplementedError("not possible to have a constant vector box") - - def nonnull(self): - raise NotImplementedError("no value known, nonnull is unkown") - - def repr_rpython(self): - return repr_rpython(self, 'bv') - - def same_shape(self, other): - if not isinstance(other, BoxVector): - return False - # - if other.item_size == -1 or self.item_size == -1: - # fallback for tests that do not specify the size - return True - # - if self.item_type != other.item_type: - return False - if self.item_size != other.item_size: - return False - if self.item_count != other.item_count: - return False - if self.item_signed != other.item_signed: - return False - return True - - def getaccum(self): - return self.accum - -# ____________________________________________________________ - def make_hashable_int(i): from rpython.rtyper.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure @@ -815,7 +729,7 @@ ops = op.getdescr()._debug_suboperations TreeLoop.check_consistency_of_branch(ops, seen.copy()) for box in op.getfailargs() or []: - if box is not None: + if box is not None: assert not isinstance(box, Const) assert box in seen elif check_descr: 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 @@ -4,7 +4,6 @@ from rpython.jit.metainterp.optimizeopt.virtualize import OptVirtualize from rpython.jit.metainterp.optimizeopt.heap import OptHeap from rpython.jit.metainterp.optimizeopt.vstring import OptString -from rpython.jit.metainterp.optimizeopt.unroll import optimize_unroll from rpython.jit.metainterp.optimizeopt.simplify import OptSimplify from rpython.jit.metainterp.optimizeopt.pure import OptPure from rpython.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -6,8 +6,8 @@ from rpython.jit.metainterp.resume import Snapshot from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import (BoxPtr, ConstPtr, ConstInt, BoxInt, - Box, Const, BoxFloat, AbstractValue) +from rpython.jit.metainterp.history import (ConstPtr, ConstInt,Const, + AbstractValue) from rpython.rtyper.lltypesystem import llmemory from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.objectmodel import we_are_translated @@ -25,12 +25,12 @@ , (rop.UNICODESETITEM, 0, -1) ] -LOAD_COMPLEX_OBJ = [ (rop.GETARRAYITEM_GC, 0, 1) - , (rop.GETARRAYITEM_RAW, 0, 1) - , (rop.RAW_LOAD, 0, 1) - , (rop.GETINTERIORFIELD_GC, 0, 1) - , (rop.GETFIELD_GC, 0, -1) - , (rop.GETFIELD_RAW, 0, -1) +LOAD_COMPLEX_OBJ = [ (rop.GETARRAYITEM_GC_I, 0, 1) + , (rop.GETARRAYITEM_GC_F, 0, 1) + , (rop.GETARRAYITEM_RAW_I, 0, 1) + , (rop.GETARRAYITEM_RAW_F, 0, 1) + , (rop.RAW_LOAD_I, 0, 1) + , (rop.RAW_LOAD_F, 0, 1) ] class Path(object): @@ -554,9 +554,9 @@ continue intformod.inspect_operation(op,node) # definition of a new variable - if op.result is not None: + if op.type != 'v': # In SSA form. Modifications get a new variable - tracker.define(op.result, node) + tracker.define(op.result(), node) # usage of defined variables if op.is_always_pure() or op.is_final(): # normal case every arguments definition is set @@ -847,9 +847,7 @@ additive_func_source = """ def operation_{name}(self, op, node): - box_r = op.result - if not box_r: - return + box_r = op box_a0 = op.getarg(0) box_a1 = op.getarg(1) if self.is_const_integral(box_a0) and self.is_const_integral(box_a1): @@ -914,15 +912,21 @@ self.memory_refs[node] = node.memory_ref """ exec py.code.Source(array_access_source - .format(name='RAW_LOAD',raw_access=True)).compile() + .format(name='RAW_LOAD_I',raw_access=True)).compile() + exec py.code.Source(array_access_source + .format(name='RAW_LOAD_F',raw_access=True)).compile() exec py.code.Source(array_access_source .format(name='RAW_STORE',raw_access=True)).compile() exec py.code.Source(array_access_source - .format(name='GETARRAYITEM_RAW',raw_access=False)).compile() + .format(name='GETARRAYITEM_RAW_I',raw_access=False)).compile() + exec py.code.Source(array_access_source + .format(name='GETARRAYITEM_RAW_F',raw_access=False)).compile() exec py.code.Source(array_access_source .format(name='SETARRAYITEM_RAW',raw_access=False)).compile() exec py.code.Source(array_access_source - .format(name='GETARRAYITEM_GC',raw_access=False)).compile() + .format(name='GETARRAYITEM_GC_I',raw_access=False)).compile() + exec py.code.Source(array_access_source + .format(name='GETARRAYITEM_GC_F',raw_access=False)).compile() exec py.code.Source(array_access_source .format(name='SETARRAYITEM_GC',raw_access=False)).compile() del array_access_source diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -4,12 +4,11 @@ gathered with IntegralForwardModification """ -from rpython.jit.metainterp.optimizeopt.util import Renamer +from rpython.jit.metainterp.optimizeopt.renamer import Renamer from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) -from rpython.jit.metainterp.history import (ConstInt, BoxVector, - BoxFloat, BoxInt, ConstFloat, Box, Const) +from rpython.jit.metainterp.history import (ConstInt, ConstFloat, Const) from rpython.jit.metainterp.compile import ResumeGuardDescr, CompileLoopVersionDescr from rpython.rlib.objectmodel import we_are_translated 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 @@ -599,9 +599,7 @@ assert pendingfields is not None if op.getdescr() is not None: descr = op.getdescr() - assert isinstance(descr, compile.ResumeAtPositionDescr) or \ - isinstance(descr, compile.ResumeAtLoopHeaderDescr) - + assert isinstance(descr, compile.ResumeAtPositionDescr) else: descr = compile.invent_fail_descr_for_op(op.getopnum(), self) op.setdescr(descr) @@ -745,10 +743,11 @@ # These are typically removed already by OptRewrite, but it can be # dissabled and unrolling emits some SAME_AS ops to setup the # optimizier state. These needs to always be optimized out. - def optimize_MARK_OPAQUE_PTR(self, op): + def optimize_SAME_AS_I(self, op): self.make_equal_to(op, op.getarg(0)) optimize_SAME_AS_R = optimize_SAME_AS_I optimize_SAME_AS_F = optimize_SAME_AS_I dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', default=Optimizer.optimize_default) + diff --git a/rpython/jit/metainterp/optimizeopt/renamer.py b/rpython/jit/metainterp/optimizeopt/renamer.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/optimizeopt/renamer.py @@ -0,0 +1,48 @@ + +class Renamer(object): + def __init__(self): + self.rename_map = {} + + def rename_box(self, box): + return self.rename_map.get(box, box) + + def start_renaming(self, var, tovar): + self.rename_map[var] = tovar + + def rename(self, op): + for i, arg in enumerate(op.getarglist()): + arg = self.rename_map.get(arg, arg) + op.setarg(i, arg) + + if op.is_guard(): + assert isinstance(op, resoperation.GuardResOp) + op.rd_snapshot = self.rename_rd_snapshot(op.rd_snapshot) + self.rename_failargs(op) + + return True + + def rename_failargs(self, guard, clone=False): + if guard.getfailargs() is not None: + if clone: + args = guard.getfailargs()[:] + else: + args = guard.getfailargs() + for i,arg in enumerate(args): + args[i] = self.rename_map.get(arg,arg) + return args + return None + + def rename_rd_snapshot(self, snapshot, clone=False): + # snapshots are nested like the MIFrames + if snapshot is None: + return None + if clone: + boxes = snapshot.boxes[:] + else: + boxes = snapshot.boxes + for i,box in enumerate(boxes): + value = self.rename_map.get(box,box) + boxes[i] = value + # + rec_snap = self.rename_rd_snapshot(snapshot.prev, clone) + return Snapshot(rec_snap, boxes) diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -1,10 +1,9 @@ - -from rpython.jit.metainterp.history import (VECTOR,FLOAT,INT,ConstInt,BoxVector, - BoxFloat,BoxInt,ConstFloat,TargetToken,Box) +from rpython.jit.metainterp.history import (VECTOR, FLOAT, INT, + ConstInt, ConstFloat, TargetToken) from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) -from rpython.jit.metainterp.optimizeopt.util import Renamer +from rpython.jit.metainterp.optimizeopt.renamer import Renamer from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.jitexc import NotAProfitableLoop @@ -705,9 +704,12 @@ rop.VEC_FLOAT_NE: OpToVectorOp((PT_FLOAT_GENERIC,PT_FLOAT_GENERIC), INT_RES), rop.VEC_INT_IS_TRUE: OpToVectorOp((PT_INT_GENERIC,PT_INT_GENERIC), PT_INT_GENERIC), - rop.VEC_RAW_LOAD: LOAD_TRANS, - rop.VEC_GETARRAYITEM_RAW: LOAD_TRANS, - rop.VEC_GETARRAYITEM_GC: LOAD_TRANS, + rop.VEC_RAW_LOAD_I: LOAD_TRANS, + rop.VEC_RAW_LOAD_F: LOAD_TRANS, + rop.VEC_GETARRAYITEM_RAW_I: LOAD_TRANS, + rop.VEC_GETARRAYITEM_RAW_F: LOAD_TRANS, + rop.VEC_GETARRAYITEM_GC_I: LOAD_TRANS, + rop.VEC_GETARRAYITEM_GC_F: LOAD_TRANS, rop.VEC_RAW_STORE: STORE_TRANS, rop.VEC_SETARRAYITEM_RAW: STORE_TRANS, rop.VEC_SETARRAYITEM_GC: STORE_TRANS, diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -28,7 +28,7 @@ def parse_loop(self, ops): loop = self.parse(ops, postprocess=self.postprocess) token = JitCellToken() - loop.operations = [ResOperation(rop.LABEL, loop.inputargs, None, + loop.operations = [ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token))] + loop.operations if loop.operations[-1].getopnum() == rop.JUMP: loop.operations[-1].setdescr(token) @@ -135,7 +135,6 @@ i = IndexVar(b,1,1,0) j = IndexVar(b,1,1,0) assert i.is_identity() - assert not i.less(j) assert i.same_variable(j) assert i.constant_diff(j) == 0 @@ -563,16 +562,7 @@ def getdescr(self): return self.descr -FLOAT = ArrayDescr(lltype.Float) -SFLOAT = ArrayDescr(lltype.SingleFloat) -CHAR = ArrayDescr(rffi.r_signedchar) -UCHAR = ArrayDescr(rffi.r_uchar) -SHORT = ArrayDescr(rffi.r_short) -USHORT = ArrayDescr(rffi.r_ushort) -INT = ArrayDescr(rffi.r_int) -UINT = ArrayDescr(rffi.r_uint) -LONG = ArrayDescr(rffi.r_longlong) -ULONG = ArrayDescr(rffi.r_ulonglong) +FLOAT = ArrayDescr(lltype.GcArray(lltype.Float), None) def memoryref(array, var, mod=(1,1,0), descr=None, raw=False): if descr is None: diff --git a/rpython/jit/metainterp/optimizeopt/vectorize.py b/rpython/jit/metainterp/optimizeopt/vectorize.py --- a/rpython/jit/metainterp/optimizeopt/vectorize.py +++ b/rpython/jit/metainterp/optimizeopt/vectorize.py @@ -10,21 +10,20 @@ from rpython.jit.metainterp.resume import Snapshot from rpython.jit.metainterp.jitexc import NotAVectorizeableLoop, NotAProfitableLoop -from rpython.jit.metainterp.optimizeopt.unroll import optimize_unroll +#from rpython.jit.metainterp.optimizeopt.unroll import optimize_unroll from rpython.jit.metainterp.compile import (ResumeAtLoopHeaderDescr, CompileLoopVersionDescr, invent_fail_descr_for_op, ResumeGuardDescr) -from rpython.jit.metainterp.history import (ConstInt, VECTOR, FLOAT, INT, - BoxVector, BoxFloat, BoxInt, ConstFloat, TargetToken, JitCellToken, Box, - LoopVersion, Accum, AbstractFailDescr) +from rpython.jit.metainterp.history import (INT, FLOAT, VECTOR, ConstInt, ConstFloat, + TargetToken, JitCellToken, LoopVersion, AbstractFailDescr) from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization -from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method, Renamer +from rpython.jit.metainterp.optimizeopt.renamer import Renamer from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleData, Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, getunpackopnum, PackType, determine_input_output_types) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt -from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) +from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) from rpython.rlib import listsort from rpython.rlib.objectmodel import we_are_translated from rpython.rlib.debug import debug_print, debug_start, debug_stop @@ -36,8 +35,8 @@ """ Enter the world of SIMD instructions. Bails if it cannot transform the trace. """ - optimize_unroll(metainterp_sd, jitdriver_sd, loop, optimizations, - inline_short_preamble, start_state, False) + #optimize_unroll(metainterp_sd, jitdriver_sd, loop, optimizations, + # inline_short_preamble, start_state, False) user_code = not jitdriver_sd.vec and warmstate.vec_all if user_code and user_loop_bail_fast_path(loop, warmstate): return @@ -332,8 +331,6 @@ if memref_a.is_adjacent_after(memref_b): pair = self.packset.can_be_packed(node_a, node_b, None, False) if pair: - if node_a.op.getopnum() == rop.GETARRAYITEM_RAW: - print " => found", memref_a.index_var, memref_b.index_var self.packset.add_pack(pair) def extend_packset(self): diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -65,7 +65,7 @@ def ResOperation(opnum, args, descr=None): cls = opclasses[opnum] - op = cls(result) + op = cls() op.initarglist(args) if descr is not None: assert isinstance(op, ResOpWithDescr) @@ -527,6 +527,92 @@ from rpython.jit.metainterp import history return history.ConstPtr(self.getref_base()) +class Accum(object): + PLUS = '+' + MULTIPLY = '*' + + def __init__(self, opnum, var, pos): + self.var = var + self.pos = pos + self.operator = Accum.PLUS + if opnum == rop.FLOAT_MUL: + self.operator = Accum.MULTIPLY + + def getoriginalbox(self): + return self.var + + def getop(self): + return self.operator + + def accumulates_value(self): + return True + +class VectorOp(object): + _mixin_ = True + _attrs_ = ('item_type','item_count','item_size','item_signed','accum') + _extended_display = False + + type = 'V' + + #def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): + # assert item_type in (FLOAT, INT) + # self.item_type = item_type + # self.item_count = item_count + # self.item_size = item_size + # self.item_signed = item_signed + # self.accum = None + + def gettype(self): + return self.item_type + + def getsize(self): + return self.item_size + + def getsigned(self): + return self.item_signed + + def getcount(self): + return self.item_count + + def fully_packed(self, vec_reg_size): + return self.item_size * self.item_count == vec_reg_size + + def forget_value(self): + raise NotImplementedError("cannot forget value of vector") + + def clonebox(self): + return BoxVector(self.item_type, self.item_count, self.item_size, self.item_signed) + + def constbox(self): + raise NotImplementedError("not possible to have a constant vector box") + + def nonnull(self): + raise NotImplementedError("no value known, nonnull is unkown") + + def repr_rpython(self): + return repr_rpython(self, 'bv') + + def same_shape(self, other): + if not isinstance(other, BoxVector): + return False + # + if other.item_size == -1 or self.item_size == -1: + # fallback for tests that do not specify the size + return True + # + if self.item_type != other.item_type: + return False + if self.item_size != other.item_size: + return False + if self.item_count != other.item_count: + return False + if self.item_signed != other.item_signed: + return False + return True + + def getaccum(self): + return self.accum + class AbstractInputArg(AbstractResOpOrInputArg): def set_forwarded(self, forwarded_to): @@ -753,6 +839,7 @@ 'GUARD_NOT_FORCED_2/0d/n', # same as GUARD_NOT_FORCED, but for finish() 'GUARD_NOT_INVALIDATED/0d/n', 'GUARD_FUTURE_CONDITION/0d/n', + 'GUARD_EARLY_EXIT/0d/n', # is removable, may be patched by an optimization '_GUARD_LAST', # ----- end of guard operations ----- @@ -787,42 +874,43 @@ # vector operations '_VEC_PURE_FIRST', '_VEC_ARITHMETIC_FIRST', - 'VEC_INT_ADD/2', - 'VEC_INT_SUB/2', - 'VEC_INT_MUL/2', - 'VEC_INT_AND/2', - 'VEC_INT_OR/2', - 'VEC_INT_XOR/2', - 'VEC_FLOAT_ADD/2', - 'VEC_FLOAT_SUB/2', - 'VEC_FLOAT_MUL/2', - 'VEC_FLOAT_TRUEDIV/2', - 'VEC_FLOAT_NEG/1', - 'VEC_FLOAT_ABS/1', + 'VEC_INT_ADD/2/i', + 'VEC_INT_SUB/2/i', + 'VEC_INT_MUL/2/i', + 'VEC_INT_AND/2/i', + 'VEC_INT_OR/2/i', + 'VEC_INT_XOR/2/i', + 'VEC_FLOAT_ADD/2/f', + 'VEC_FLOAT_SUB/2/f', + 'VEC_FLOAT_MUL/2/f', + 'VEC_FLOAT_TRUEDIV/2/f', + 'VEC_FLOAT_NEG/1/f', + 'VEC_FLOAT_ABS/1/f', '_VEC_ARITHMETIC_LAST', - 'VEC_FLOAT_EQ/2b', - 'VEC_FLOAT_NE/2b', - 'VEC_INT_IS_TRUE/1b', - 'VEC_INT_NE/2b', - 'VEC_INT_EQ/2b', + 'VEC_FLOAT_EQ/2b/f', + 'VEC_FLOAT_NE/2b/f', + 'VEC_INT_IS_TRUE/1b/i', + 'VEC_INT_NE/2b/i', + 'VEC_INT_EQ/2b/i', '_VEC_CAST_FIRST', - 'VEC_INT_SIGNEXT/2', + 'VEC_INT_SIGNEXT/2/i', # double -> float: v2 = cast(v1, 2) equal to v2 = (v1[0], v1[1], X, X) - 'VEC_CAST_FLOAT_TO_SINGLEFLOAT/1', + 'VEC_CAST_FLOAT_TO_SINGLEFLOAT/1/i', # v4 = cast(v3, 0, 2), v4 = (v3[0], v3[1]) - 'VEC_CAST_SINGLEFLOAT_TO_FLOAT/1', - 'VEC_CAST_FLOAT_TO_INT/1', - 'VEC_CAST_INT_TO_FLOAT/1', + 'VEC_CAST_SINGLEFLOAT_TO_FLOAT/1/f', + 'VEC_CAST_FLOAT_TO_INT/1/i', + 'VEC_CAST_INT_TO_FLOAT/1/f', '_VEC_CAST_LAST', - 'VEC_FLOAT_UNPACK/3', # iX|fX = VEC_FLOAT_UNPACK(vX, index, item_count) - 'VEC_FLOAT_PACK/4', # VEC_FLOAT_PACK(vX, var/const, index, item_count) - 'VEC_INT_UNPACK/3', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) - 'VEC_INT_PACK/4', # VEC_INT_PACK(vX, var/const, index, item_count) - 'VEC_FLOAT_EXPAND/2', # vX = VEC_FLOAT_EXPAND(var/const, item_count) - 'VEC_INT_EXPAND/2', # vX = VEC_INT_EXPAND(var/const, item_count) - 'VEC_BOX/1', + 'VEC_INT_BOX/1/i', + 'VEC_INT_UNPACK/3/i', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) + 'VEC_INT_PACK/4/i', # VEC_INT_PACK(vX, var/const, index, item_count) + 'VEC_INT_EXPAND/2/i', # vX = VEC_INT_EXPAND(var/const, item_count) + 'VEC_FLOAT_BOX/1/f', + 'VEC_FLOAT_UNPACK/3/f', # iX|fX = VEC_FLOAT_UNPACK(vX, index, item_count) + 'VEC_FLOAT_PACK/4/f', # VEC_FLOAT_PACK(vX, var/const, index, item_count) + 'VEC_FLOAT_EXPAND/2/f', # vX = VEC_FLOAT_EXPAND(var/const, item_count) '_VEC_PURE_LAST', # 'INT_LT/2b/i', @@ -872,11 +960,11 @@ '_RAW_LOAD_FIRST', 'GETARRAYITEM_GC/2d/rfi', - 'VEC_GETARRAYITEM_GC/3d', + 'VEC_GETARRAYITEM_GC/3d/fi', 'GETARRAYITEM_RAW/2d/fi', - 'VEC_GETARRAYITEM_RAW/3d', + 'VEC_GETARRAYITEM_RAW/3d/fi', 'RAW_LOAD/2d/fi', - 'VEC_RAW_LOAD/3d', + 'VEC_RAW_LOAD/3d/fi', '_RAW_LOAD_LAST', 'GETINTERIORFIELD_GC/2d/rfi', @@ -899,11 +987,11 @@ 'INCREMENT_DEBUG_COUNTER/1/n', '_RAW_STORE_FIRST', 'SETARRAYITEM_GC/3d/n', - 'VEC_SETARRAYITEM_GC/3d', + 'VEC_SETARRAYITEM_GC/3d/n', 'SETARRAYITEM_RAW/3d/n', - 'VEC_SETARRAYITEM_RAW/3d', + 'VEC_SETARRAYITEM_RAW/3d/n', 'RAW_STORE/3d/n', - 'VEC_RAW_STORE/3d', + 'VEC_RAW_STORE/3d/n', '_RAW_STORE_LAST', 'SETINTERIORFIELD_GC/3d/n', 'SETINTERIORFIELD_RAW/3d/n', # right now, only used by tests @@ -1000,7 +1088,7 @@ for r in result: if len(result) == 1: cls_name = name - else: + else: cls_name = name + '_' + r.upper() setattr(rop, cls_name, i) opname[i] = cls_name @@ -1126,13 +1214,18 @@ rop.PTR_NE: rop.PTR_NE, } _opvector = { - rop.RAW_LOAD: rop.VEC_RAW_LOAD, - rop.GETARRAYITEM_RAW: rop.VEC_GETARRAYITEM_RAW, - rop.GETARRAYITEM_GC: rop.VEC_GETARRAYITEM_GC, + rop.RAW_LOAD_I: rop.VEC_RAW_LOAD_I, + rop.RAW_LOAD_F: rop.VEC_RAW_LOAD_F, + rop.GETARRAYITEM_RAW_I: rop.VEC_GETARRAYITEM_RAW_I, + rop.GETARRAYITEM_RAW_F: rop.VEC_GETARRAYITEM_RAW_F, + rop.GETARRAYITEM_GC_I: rop.VEC_GETARRAYITEM_GC_I, + rop.GETARRAYITEM_GC_F: rop.VEC_GETARRAYITEM_GC_F, # note that there is no _PURE operation for vector operations. # reason: currently we do not care if it is pure or not! - rop.GETARRAYITEM_RAW_PURE: rop.VEC_GETARRAYITEM_RAW, - rop.GETARRAYITEM_GC_PURE: rop.VEC_GETARRAYITEM_GC, + rop.GETARRAYITEM_RAW_PURE_I: rop.VEC_GETARRAYITEM_RAW_I, + rop.GETARRAYITEM_RAW_PURE_F: rop.VEC_GETARRAYITEM_RAW_F, + rop.GETARRAYITEM_GC_PURE_I: rop.VEC_GETARRAYITEM_GC_I, + rop.GETARRAYITEM_GC_PURE_F: rop.VEC_GETARRAYITEM_GC_F, rop.RAW_STORE: rop.VEC_RAW_STORE, rop.SETARRAYITEM_RAW: rop.VEC_SETARRAYITEM_RAW, rop.SETARRAYITEM_GC: rop.VEC_SETARRAYITEM_GC, From noreply at buildbot.pypy.org Thu Sep 10 14:29:13 2015 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 10 Sep 2015 14:29:13 +0200 (CEST) Subject: [pypy-commit] pypy default: fix more tests Message-ID: <20150910122913.EBE591C1453@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79583:605318757f6b Date: 2015-09-10 15:29 +0300 http://bitbucket.org/pypy/pypy/changeset/605318757f6b/ Log: fix more tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -43,9 +43,9 @@ i25 = unicodegetitem(p13, i19) p27 = newstr(1) strsetitem(p27, 0, i23) - p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) + p30 = call_r(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) guard_no_exception(descr=...) - i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) + i32 = call_i(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- @@ -80,12 +80,12 @@ i23 = strgetitem(p10, i19) p25 = newstr(1) strsetitem(p25, 0, i23) - p93 = call(ConstClass(fromstr), p25, 16, descr=) + p93 = call_r(ConstClass(fromstr), p25, 16, descr=) guard_no_exception(descr=...) - i95 = getfield_gc_pure(p93, descr=) + i95 = getfield_gc_pure_i(p93, descr=) i96 = int_gt(i95, #) guard_false(i96, descr=...) - i94 = call(ConstClass(rbigint._toint_helper), p93, descr=) + i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=) guard_no_exception(descr=...) i95 = int_add_ovf(i6, i94) guard_no_overflow(descr=...) @@ -108,7 +108,7 @@ i79 = int_gt(i74, 0) guard_true(i79, descr=...) guard_not_invalidated(descr=...) - p80 = call(ConstClass(ll_int2dec__Signed), i74, descr=) + p80 = call_r(ConstClass(ll_int2dec__Signed), i74, descr=) guard_no_exception(descr=...) i85 = strlen(p80) p86 = new(descr=) @@ -119,21 +119,21 @@ setfield_gc(p86, 23, descr=) setfield_gc(p86, 23, descr=) }}} - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - i89 = getfield_gc(p86, descr=) - i90 = getfield_gc(p86, descr=) + i89 = getfield_gc_i(p86, descr=) + i90 = getfield_gc_i(p86, descr=) i91 = int_eq(i89, i90) cond_call(i91, ConstClass(ll_grow_by__stringbuilderPtr_Signed), p86, 1, descr=) guard_no_exception(descr=...) - i92 = getfield_gc(p86, descr=) + i92 = getfield_gc_i(p86, descr=) i93 = int_add(i92, 1) p94 = getfield_gc(p86, descr=) strsetitem(p94, i92, 32) setfield_gc(p86, i93, descr=) - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - p95 = call(..., descr=) # ll_build + p95 = call_r(..., descr=) # ll_build guard_no_exception(descr=...) i96 = strlen(p95) i97 = int_add_ovf(i71, i96) @@ -176,7 +176,7 @@ strsetitem(p35, 3, 104) strsetitem(p35, 4, 95) copystrcontent(p31, p35, 0, 5, i32) - i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) + i49 = call_i(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) guard_value(i49, 1, descr=...) ''') @@ -195,7 +195,7 @@ loops = log.loops_by_filename(self.filepath) loop, = loops assert loop.match_by_id('callone', ''' - p114 = call(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) + p114 = call_r(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) guard_no_exception(descr=...) ''') assert loop.match_by_id('calltwo', '') # nothing diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py --- a/pypy/module/pypyjit/test_pypy_c/test_thread.py +++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py @@ -64,11 +64,11 @@ guard_true(i56, descr=...) p57 = force_token() setfield_gc(p0, p57, descr=) - i58 = call_release_gil(0, _, i37, 1, descr=) + i58 = call_release_gil_i(0, _, i37, 1, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) i58 = int_sub(i44, 1) - i59 = call(ConstClass(RPyThreadReleaseLock), i37, descr=) + i59 = call_i(ConstClass(RPyThreadReleaseLock), i37, descr=) i60 = int_is_true(i59) guard_false(i60, descr=...) guard_not_invalidated(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_weakref.py b/pypy/module/pypyjit/test_pypy_c/test_weakref.py --- a/pypy/module/pypyjit/test_pypy_c/test_weakref.py +++ b/pypy/module/pypyjit/test_pypy_c/test_weakref.py @@ -19,23 +19,23 @@ """, [500]) loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i58 = getfield_gc(p18, descr=) + i58 = getfield_gc_i(p18, descr=) i60 = int_lt(i58, i31) guard_true(i60, descr=...) i61 = int_add(i58, 1) - p62 = getfield_gc(ConstPtr(ptr37), descr=) + p62 = getfield_gc_r(ConstPtr(ptr37), descr=) setfield_gc(p18, i61, descr=) guard_value(p62, ConstPtr(ptr39), descr=...) guard_not_invalidated(descr=...) - p64 = getfield_gc(ConstPtr(ptr40), descr=) + p64 = getfield_gc_r(ConstPtr(ptr40), descr=) guard_value(p64, ConstPtr(ptr42), descr=...) - p65 = getfield_gc(p14, descr=) + p65 = getfield_gc_r(p14, descr=) guard_value(p65, ConstPtr(ptr45), descr=...) - p66 = getfield_gc(p14, descr=) + p66 = getfield_gc_r(p14, descr=) guard_nonnull_class(p66, ..., descr=...) p67 = force_token() setfield_gc(p0, p67, descr=) - p68 = call_may_force(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) + p68 = call_may_force_r(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) guard_nonnull_class(p68, ..., descr=...) From noreply at buildbot.pypy.org Thu Sep 10 14:38:47 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 10 Sep 2015 14:38:47 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: dependency tests pass again Message-ID: <20150910123847.DEE161C1453@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79584:8e6bb4ab9549 Date: 2015-09-10 14:38 +0200 http://bitbucket.org/pypy/pypy/changeset/8e6bb4ab9549/ Log: dependency tests pass again diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -27,10 +27,20 @@ LOAD_COMPLEX_OBJ = [ (rop.GETARRAYITEM_GC_I, 0, 1) , (rop.GETARRAYITEM_GC_F, 0, 1) + , (rop.GETARRAYITEM_GC_R, 0, 1) , (rop.GETARRAYITEM_RAW_I, 0, 1) , (rop.GETARRAYITEM_RAW_F, 0, 1) , (rop.RAW_LOAD_I, 0, 1) , (rop.RAW_LOAD_F, 0, 1) + , (rop.GETINTERIORFIELD_GC_I, 0, 1) + , (rop.GETINTERIORFIELD_GC_F, 0, 1) + , (rop.GETINTERIORFIELD_GC_R, 0, 1) + , (rop.GETFIELD_GC_I, 0, -1) + , (rop.GETFIELD_GC_F, 0, -1) + , (rop.GETFIELD_GC_R, 0, -1) + , (rop.GETFIELD_RAW_I, 0, -1) + , (rop.GETFIELD_RAW_F, 0, -1) + , (rop.GETFIELD_RAW_R, 0, -1) ] class Path(object): @@ -209,7 +219,7 @@ # if it is a constant argument it cannot be destroyed. # neither can a box float be destroyed. BoxInt can # contain a reference thus it is assumed to be destroyed - if isinstance(arg, Const) or isinstance(arg, BoxFloat): + if arg.is_constant() or arg.type == 'f': args.append((arg, None, False)) else: args.append((arg, None, True)) @@ -556,7 +566,7 @@ # definition of a new variable if op.type != 'v': # In SSA form. Modifications get a new variable - tracker.define(op.result(), node) + tracker.define(op, node) # usage of defined variables if op.is_always_pure() or op.is_final(): # normal case every arguments definition is set @@ -604,10 +614,10 @@ if guard_opnum in (rop.GUARD_TRUE, rop.GUARD_FALSE): for dep in guard_node.depends(): op = dep.to.getoperation() - if op.returns_bool_result() and op.result == guard_op.getarg(0): + if op.returns_bool_result() and op is guard_op.getarg(0): guard_node.guard_bool_bool_node = dep.to for arg in op.getarglist(): - if isinstance(arg, Box): + if not arg.is_constant(): self.guard_exit_dependence(guard_node, arg, tracker) break else: @@ -619,7 +629,7 @@ elif guard_op.is_foldable_guard(): # these guards carry their protected variables directly as a parameter for arg in guard_node.getoperation().getarglist(): - if isinstance(arg, Box): + if not arg.is_constant(): self.guard_exit_dependence(guard_node, arg, tracker) elif guard_opnum == rop.GUARD_NOT_FORCED_2: # must be emitted before finish, thus delayed the longest @@ -873,7 +883,7 @@ multiplicative_func_source = """ def operation_{name}(self, op, node): - box_r = op.result + box_r = op if not box_r: return box_a0 = op.getarg(0) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -302,7 +302,7 @@ def test_exception_dep(self): ops=""" [p0, i1, i2] # 0: 1,3? - i4 = call(p0, 1, descr=nonwritedescr) # 1: 2,3 + i4 = call_i(p0, 1, descr=nonwritedescr) # 1: 2,3 guard_no_exception() [] # 2: 3 jump(p0, i1, i2) # 3: """ @@ -312,9 +312,9 @@ ops=""" [p0, p1, i2] # 0: 1,2?,3?,4?,5? i3 = int_add(i2,1) # 1: 2 - i4 = call(p0, i3, descr=nonwritedescr) # 2: 3,4,5? + i4 = call_i(p0, i3, descr=nonwritedescr) # 2: 3,4,5? guard_no_exception() [i2] # 3: 4?,5? - p2 = getarrayitem_gc(p1,i3,descr=intarraydescr) # 4: 5 + p2 = getarrayitem_gc_r(p1, i3, descr=arraydescr) # 4: 5 jump(p2, p1, i3) # 5: """ self.assert_dependencies(ops, full_check=True) @@ -323,9 +323,9 @@ ops=""" [p0, p1, i2, i5] # 0: 1,2?,3?,4?,5? i3 = int_add(i2,1) # 1: 2 - i4 = call(i5, i3, descr=nonwritedescr) # 2: 3,4,5? + i4 = call_i(i5, i3, descr=nonwritedescr) # 2: 3,4,5? guard_no_exception() [i2] # 3: 5? - p2 = getarrayitem_gc(p1,i3,descr=chararraydescr) # 4: 5 + p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 4: 5 jump(p2, p1, i3, i5) # 5: """ self.assert_dependencies(ops, full_check=True) @@ -333,11 +333,11 @@ def test_not_forced(self): ops=""" [p0, p1, i2, i5] # 0: 1,2,4?,5,6 - i4 = call(i5, i2, descr=nonwritedescr) # 1: 2,4,6 + i4 = call_i(i5, i2, descr=nonwritedescr) # 1: 2,4,6 guard_not_forced() [i2] # 2: 3 guard_no_exception() [] # 3: 6 i3 = int_add(i2,1) # 4: 5 - p2 = getarrayitem_gc(p1,i3,descr=chararraydescr) # 5: 6 + p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 5: 6 jump(p2, p1, i2, i5) # 6: """ self.assert_dependencies(ops, full_check=True) @@ -348,7 +348,7 @@ ops=""" [p0, i1] # 0: 1,2?,3?,4? setarrayitem_raw(p0, i1, 1, descr=floatarraydescr) # 1: 2,3 - i2 = getarrayitem_raw(p0, i1, descr=floatarraydescr) # 2: 4 + i2 = getarrayitem_raw_i(p0, i1, descr=floatarraydescr) # 2: 4 setarrayitem_raw(p0, i1, 2, descr=floatarraydescr) # 3: 4 jump(p0, i2) # 4: """ @@ -383,22 +383,22 @@ ops = """ [i0, i1, i2, i3, i4, i5, i6, i7] # 0: 1,2,3,4,6,7,8,9,10,12,14,17,19,20,21 i9 = int_mul(i0, 8) # 1: 2 - i10 = raw_load(i3, i9, descr=intarraydescr) # 2: 5, 10 + i10 = raw_load_i(i3, i9, descr=arraydescr) # 2: 5, 10 i11 = int_mul(i0, 8) # 3: 4 - i12 = raw_load(i4, i11, descr=intarraydescr) # 4: 5,10 + i12 = raw_load_i(i4, i11, descr=arraydescr) # 4: 5,10 i13 = int_add(i10, i12) # 5: 7,10 i14 = int_mul(i0, 8) # 6: 7 - raw_store(i5, i14, i13, descr=intarraydescr) # 7: 21 + raw_store(i5, i14, i13, descr=arraydescr) # 7: 21 i16 = int_add(i0, 1) # 8: 9,10,11,13,16,18 i17 = int_lt(i16, i7) # 9: 10 guard_true(i17) [i7, i13, i5, i4, i3, i12, i10, i16] # 10: 11,13,16,18,19,21 i18 = int_mul(i16, 8) # 11: - i19 = raw_load(i3, i18, descr=intarraydescr) # 12: + i19 = raw_load_i(i3, i18, descr=arraydescr) # 12: i20 = int_mul(i16, 8) # 13: - i21 = raw_load(i4, i20, descr=intarraydescr) # 14: + i21 = raw_load_i(i4, i20, descr=arraydescr) # 14: i22 = int_add(i19, i21) # 15: i23 = int_mul(i16, 8) # 16: - raw_store(i5, i23, i22, descr=intarraydescr) # 17: + raw_store(i5, i23, i22, descr=arraydescr) # 17: i24 = int_add(i16, 1) # 18: i25 = int_lt(i24, i7) # 19: guard_true(i25) [i7, i22, i5, i4, i3, i21, i19, i24] # 20: @@ -408,11 +408,10 @@ self.assert_dependent(2,12) def test_getfield(self): - pass trace = """ [p0, p1] # 0: 1,2,5 - p2 = getfield_gc(p0) # 1: 3,5 - p3 = getfield_gc(p0) # 2: 4 + p2 = getfield_gc_r(p0) # 1: 3,5 + p3 = getfield_gc_r(p0) # 2: 4 guard_nonnull(p2) [p2] # 3: 4,5 guard_nonnull(p3) [p3] # 4: 5 jump(p0,p2) # 5: @@ -424,10 +423,10 @@ trace = """ [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6 guard_early_exit() [] # 1: 2,4,6,7 - p13 = getfield_gc(p9) # 2: 3,5,6 + p13 = getfield_gc_r(p9) # 2: 3,5,6 guard_nonnull(p13) [] # 3: 5,6 - i14 = getfield_gc(p9) # 4: 6 - p15 = getfield_gc(p13) # 5: 6 + i14 = getfield_gc_i(p9) # 4: 6 + p15 = getfield_gc_r(p13) # 5: 6 guard_class(p15, 140737326900656) [p1, p0, p9, i14, p15, p13, p5, p6, p7] # 6: 7 jump(p0,p1,p5,p6,p7,p9,p11,p12) # 7: """ From noreply at buildbot.pypy.org Thu Sep 10 18:30:50 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 10 Sep 2015 18:30:50 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: adapted optimization entry to fit into the new model. going forward, but still not yet complete to run the first simple loops Message-ID: <20150910163050.321B11C0362@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79585:efc1fdaa1cee Date: 2015-09-10 18:30 +0200 http://bitbucket.org/pypy/pypy/changeset/efc1fdaa1cee/ Log: adapted optimization entry to fit into the new model. going forward, but still not yet complete to run the first simple loops diff too long, truncating to 2000 out of 6555 lines diff --git a/rpython/jit/backend/x86/test/test_vectorize.py b/rpython/jit/backend/x86/test/test_vectorize.py deleted file mode 100644 --- a/rpython/jit/backend/x86/test/test_vectorize.py +++ /dev/null @@ -1,78 +0,0 @@ -import py -from rpython.jit.backend.x86.regloc import * -from rpython.jit.backend.x86.test import test_basic -from rpython.jit.backend.x86.test.test_assembler import \ - (TestRegallocPushPop as BaseTestAssembler) -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.metainterp.history import ConstFloat -from rpython.jit.metainterp.test import support, test_vectorize -from rpython.jit.metainterp.warmspot import ll_meta_interp -from rpython.rlib.jit import JitDriver -from rpython.rtyper.lltypesystem import lltype - - -class TestBasic(test_vectorize.VectorizeLLtypeTests, test_basic.Jit386Mixin): - # for the individual tests see - # ====> ../../../metainterp/test/test_basic.py - enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' - -class TestAssembler(BaseTestAssembler): - def imm_4_int32(self, a, b, c, d): - adr = self.xrm.assembler.datablockwrapper.malloc_aligned(16, 16) - ptr = rffi.cast(rffi.CArrayPtr(rffi.INT), adr) - ptr[0] = rffi.r_int(a) - ptr[1] = rffi.r_int(b) - ptr[2] = rffi.r_int(c) - ptr[3] = rffi.r_int(d) - return adr - - def test_simple_4_int_load_sum_x86_64(self): - def callback(asm): - if asm.mc.WORD != 8: - py.test.skip() - adr = self.imm_4_int32(123,543,0,0) - asm.mc.MOV_ri(r8.value,adr) - asm.mc.MOVDQU_xm(xmm7.value, (r8.value, 0)) - asm.mc.PADDD_xm(xmm7.value, (r8.value, 0)) - asm.mc.PADDD_xx(xmm7.value, xmm7.value) - - asm.mc.MOV_ri(edx.value, 0x00000000ffffffff) - - asm.mc.MOV_ri(eax.value, 0) - asm.mc.MOVDQ_rx(ecx.value, xmm7.value) - asm.mc.AND_rr(ecx.value, edx.value) - asm.mc.ADD(eax, ecx) - - asm.mc.PSRLDQ_xi(xmm7.value, 4) - asm.mc.MOVDQ_rx(ecx.value, xmm7.value) - asm.mc.AND_rr(ecx.value, edx.value) - asm.mc.ADD(eax, ecx) - res = self.do_test(callback) - assert res == 123*4 + 543*4 - - def test_vector_store(self): - def callback(asm): - addr = self.imm_4_int32(11,12,13,14) - asm.mov(ImmedLoc(addr), ecx) - asm.mc.MOVDQU_xm(xmm6.value, (ecx.value,0)) - asm.mc.PADDD_xm(xmm6.value, (ecx.value,0)) - asm.mc.MOVDQU(AddressLoc(ecx,ImmedLoc(0)), xmm6) - asm.mc.MOVDQU(xmm6, AddressLoc(ecx,ImmedLoc(0))) - asm.mc.MOVDQ_rx(eax.value, xmm6.value) - - res = self.do_test(callback) & 0xffffffff - assert res == 22 - - - def test_vector_store_aligned(self): - def callback(asm): - addr = self.imm_4_int32(11,12,13,14) - asm.mov(ImmedLoc(addr), ecx) - asm.mc.MOVDQA(xmm6, AddressLoc(ecx,ImmedLoc(0))) - asm.mc.PADDD_xm(xmm6.value, (ecx.value,0)) - asm.mc.MOVDQA(AddressLoc(ecx,ImmedLoc(0)), xmm6) - asm.mc.MOVDQA(xmm6, AddressLoc(ecx,ImmedLoc(0))) - asm.mc.MOVDQ_rx(eax.value, xmm6.value) - - res = self.do_test(callback) & 0xffffffff - assert res == 22 diff --git a/rpython/jit/backend/x86/test/test_x86vector.py b/rpython/jit/backend/x86/test/test_x86vector.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/test/test_x86vector.py @@ -0,0 +1,78 @@ +import py +from rpython.jit.backend.x86.regloc import * +from rpython.jit.backend.x86.test import test_basic +from rpython.jit.backend.x86.test.test_assembler import \ + (TestRegallocPushPop as BaseTestAssembler) +from rpython.jit.backend.detect_cpu import getcpuclass +from rpython.jit.metainterp.history import ConstFloat +from rpython.jit.metainterp.test import support, test_metavec +from rpython.jit.metainterp.warmspot import ll_meta_interp +from rpython.rlib.jit import JitDriver +from rpython.rtyper.lltypesystem import lltype + + +class TestBasic(test_metavec.VectorizeLLtypeTests, test_basic.Jit386Mixin): + # for the individual tests see + # ====> ../../../metainterp/test/test_basic.py + enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' + +class TestAssembler(BaseTestAssembler): + def imm_4_int32(self, a, b, c, d): + adr = self.xrm.assembler.datablockwrapper.malloc_aligned(16, 16) + ptr = rffi.cast(rffi.CArrayPtr(rffi.INT), adr) + ptr[0] = rffi.r_int(a) + ptr[1] = rffi.r_int(b) + ptr[2] = rffi.r_int(c) + ptr[3] = rffi.r_int(d) + return adr + + def test_simple_4_int_load_sum_x86_64(self): + def callback(asm): + if asm.mc.WORD != 8: + py.test.skip() + adr = self.imm_4_int32(123,543,0,0) + asm.mc.MOV_ri(r8.value,adr) + asm.mc.MOVDQU_xm(xmm7.value, (r8.value, 0)) + asm.mc.PADDD_xm(xmm7.value, (r8.value, 0)) + asm.mc.PADDD_xx(xmm7.value, xmm7.value) + + asm.mc.MOV_ri(edx.value, 0x00000000ffffffff) + + asm.mc.MOV_ri(eax.value, 0) + asm.mc.MOVDQ_rx(ecx.value, xmm7.value) + asm.mc.AND_rr(ecx.value, edx.value) + asm.mc.ADD(eax, ecx) + + asm.mc.PSRLDQ_xi(xmm7.value, 4) + asm.mc.MOVDQ_rx(ecx.value, xmm7.value) + asm.mc.AND_rr(ecx.value, edx.value) + asm.mc.ADD(eax, ecx) + res = self.do_test(callback) + assert res == 123*4 + 543*4 + + def test_vector_store(self): + def callback(asm): + addr = self.imm_4_int32(11,12,13,14) + asm.mov(ImmedLoc(addr), ecx) + asm.mc.MOVDQU_xm(xmm6.value, (ecx.value,0)) + asm.mc.PADDD_xm(xmm6.value, (ecx.value,0)) + asm.mc.MOVDQU(AddressLoc(ecx,ImmedLoc(0)), xmm6) + asm.mc.MOVDQU(xmm6, AddressLoc(ecx,ImmedLoc(0))) + asm.mc.MOVDQ_rx(eax.value, xmm6.value) + + res = self.do_test(callback) & 0xffffffff + assert res == 22 + + + def test_vector_store_aligned(self): + def callback(asm): + addr = self.imm_4_int32(11,12,13,14) + asm.mov(ImmedLoc(addr), ecx) + asm.mc.MOVDQA(xmm6, AddressLoc(ecx,ImmedLoc(0))) + asm.mc.PADDD_xm(xmm6.value, (ecx.value,0)) + asm.mc.MOVDQA(AddressLoc(ecx,ImmedLoc(0)), xmm6) + asm.mc.MOVDQA(xmm6, AddressLoc(ecx,ImmedLoc(0))) + asm.mc.MOVDQ_rx(eax.value, xmm6.value) + + res = self.do_test(callback) & 0xffffffff + assert res == 22 diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -255,6 +255,12 @@ history = metainterp.history warmstate = jitdriver_sd.warmstate + enable_opts = jitdriver_sd.warmstate.enable_opts + if try_disabling_unroll: + if 'unroll' not in enable_opts: + return None + enable_opts = enable_opts.copy() + del enable_opts['unroll'] ops = history.operations[start:] if 'unroll' not in enable_opts: @@ -292,6 +298,12 @@ metainterp.box_names_memo) except InvalidLoop: return None + + if ((warmstate.vec and jitdriver_sd.vec) or warmstate.vec_all): + from rpython.jit.metainterp.optimizeopt.vector import optimize_vector + loop_info, loop_ops = optimize_vector(metainterp_sd, + jitdriver_sd, warmstate, + loop_info, loop_ops) # loop = create_empty_loop(metainterp) loop.original_jitcell_token = jitcell_token @@ -312,16 +324,15 @@ label_token.short_preamble, metainterp.box_names_memo) loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as + [loop_info.label_op] + loop_ops) + if loop.versions is not None: + # every different loop version must update their target tokens + for version in loop.versions: + version.update_token(jitcell_token, all_target_tokens) if not we_are_translated(): loop.check_consistency() send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", inputargs, metainterp.box_names_memo) - # XXX if loop.versions is not None: - # # every different loop version must update their target tokens - # for version in loop.versions: - # version.update_token(jitcell_token, all_target_tokens) - record_loop_or_bridge(metainterp_sd, loop) generate_pending_loop_versions(loop, jitdriver_sd, metainterp, jitcell_token) return start_descr diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -481,111 +481,6 @@ def repr_of_descr(self): return 'TargetToken(%d)' % compute_unique_id(self) -def index_of_first(opnum, operations, pass_by=0): - """ returns the position of the first operation matching the opnum. - Or -1 if non is found - """ - for i,op in enumerate(operations): - if op.getopnum() == opnum: - if pass_by == 0: - return i - else: - pass_by -= 1 - return -1 - -class VersionInfo(object): - def __init__(self): - self.descrs = [] - self.leads_to = {} - self.insert_index = -1 - - def mark(self): - self.insert_index = len(self.descrs) - - def clear(self): - self.insert_index = -1 - - def track(self, op, descr, version): - assert descr.loop_version() - i = self.insert_index - if i >= 0: - assert i >= 0 - self.descrs.insert(i, descr) - else: - self.descrs.append(descr) - self.leads_to[descr] = version - # note: stitching a guard must resemble the order of the label - # otherwise a wrong mapping is handed to the register allocator - op.setfailargs(version.renamed_inputargs) - assert version.renamed_inputargs is not None - - def remove(self, descr): - if descr in self.leads_to: - del self.leads_to[descr] - else: - assert 0, "could not remove %s" % descr - - def get(self, descr): - return self.leads_to.get(descr, None) - -class LoopVersion(object): - """ A special version of a trace loop. Use loop.snaphost() to - create one instance and attach it to a guard descr. - If not attached to a descriptor, it will not be compiled. - """ - inputargs = None - renamed_inputargs = None - - def __init__(self, operations): - self.operations = operations - idx = index_of_first(rop.LABEL, self.operations) - assert idx >= 0 - label = self.operations[idx] - self.inputargs = label.getarglist() - self.renamed_inputargs = label.getarglist() - - def setup_once(self, info): - for op in self.operations: - if op.is_guard(): - olddescr = op.getdescr() - if not olddescr: - continue - descr = olddescr.clone() - op.setdescr(descr) - if descr.loop_version(): - toversion = info.leads_to.get(olddescr,None) - if toversion: - info.track(op, descr, toversion) - else: - assert 0, "olddescr must be found" - - def update_token(self, jitcell_token, all_target_tokens): - # this is only invoked for versioned loops! - label_index = index_of_first(rop.LABEL, self.operations, 0) - label = self.operations[label_index] - jump = self.operations[-1] - # - assert jump.getopnum() == rop.JUMP - # - token = TargetToken(jitcell_token) - token.original_jitcell_token = jitcell_token - all_target_tokens.append(token) - if label.getdescr() is None or label.getdescr() is not jump.getdescr(): - label_index = index_of_first(rop.LABEL, self.operations, 1) - if label_index > 0: - second_label = self.operations[label_index] - # set the inner loop - second_label.setdescr(token) - jump.setdescr(token) - # set the first label - token = TargetToken(jitcell_token) - token.original_jitcell_token = jitcell_token - all_target_tokens.append(token) - label.setdescr(token) - return - label.setdescr(token) - jump.setdescr(token) - class TreeLoop(object): inputargs = None operations = None @@ -607,7 +502,6 @@ def __init__(self, name): self.name = name self.versions = [] - self.version_info = VersionInfo() # self.operations = list of ResOperations # ops of the kind 'guard_xxx' contain a further list of operations, # which may itself contain 'guard_xxx' and so on, making a tree. @@ -626,30 +520,30 @@ insns[opname] = insns.get(opname, 0) + 1 return insns - def append_loop(self, loop, all_target_tokens): - # append e.g. the peeled loop to this loop! - jump = loop.operations[-1] - assert jump.getdescr() is not None - target_token = None - i = 0 - # adds all target token until the one is found that jumps from the - # last instruction to the label - while i < len(loop.operations) and target_token is not jump.getdescr(): - # there is another label - op = loop.operations[i] - if op.getopnum() == rop.LABEL: - target_token = op.getdescr() - assert isinstance(target_token, TargetToken) - all_target_tokens.append(target_token) - i += 1 - # - self.operations = self.operations[:-1] + loop.operations - self.versions = loop.versions - loop.versions = None - self.version_info = loop.version_info - loop.version_info = None - if loop.quasi_immutable_deps: - self.quasi_immutable_deps.update(loop.quasi_immutable_deps) + # XXX VECdef append_loop(self, loop, all_target_tokens): + # XXX VEC # append e.g. the peeled loop to this loop! + # XXX VEC jump = loop.operations[-1] + # XXX VEC assert jump.getdescr() is not None + # XXX VEC target_token = None + # XXX VEC i = 0 + # XXX VEC # adds all target token until the one is found that jumps from the + # XXX VEC # last instruction to the label + # XXX VEC while i < len(loop.operations) and target_token is not jump.getdescr(): + # XXX VEC # there is another label + # XXX VEC op = loop.operations[i] + # XXX VEC if op.getopnum() == rop.LABEL: + # XXX VEC target_token = op.getdescr() + # XXX VEC assert isinstance(target_token, TargetToken) + # XXX VEC all_target_tokens.append(target_token) + # XXX VEC i += 1 + # XXX VEC # + # XXX VEC self.operations = self.operations[:-1] + loop.operations + # XXX VEC self.versions = loop.versions + # XXX VEC loop.versions = None + # XXX VEC self.version_info = loop.version_info + # XXX VEC loop.version_info = None + # XXX VEC if loop.quasi_immutable_deps: + # XXX VEC self.quasi_immutable_deps.update(loop.quasi_immutable_deps) def get_operations(self): return self.operations @@ -659,34 +553,6 @@ self.name, ', '.join([box.repr(memo) for box in self.inputargs])) - def find_first_index(self, opnum, pass_by=0): - """ return the first index of the operation having the same opnum or -1 """ - return index_of_first(opnum, self.operations, pass_by) - - def find_first(self, opnum, pass_by=0): - index = self.find_first_index(opnum, pass_by) - if index != -1: - return self.operations[index] - return None - - def snapshot(self): - oplist = self.copy_operations(self.operations) - version = LoopVersion(oplist) - version.setup_once(self.version_info) - # register the faildescr for later stitching - self.versions.append(version) - return version - - def copy_operations(self, operations): - ignore = (rop.DEBUG_MERGE_POINT,) - oplist = [] - for op in operations: - if op.getopnum() in ignore: - continue - cloned = op.clone() - oplist.append(cloned) - return oplist - def get_display_text(self): # for graphpage.py return self.name + '\n' + repr(self.inputargs) 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 @@ -7,12 +7,10 @@ from rpython.jit.metainterp.optimizeopt.simplify import OptSimplify from rpython.jit.metainterp.optimizeopt.pure import OptPure from rpython.jit.metainterp.optimizeopt.earlyforce import OptEarlyForce -from rpython.jit.metainterp.optimizeopt.vectorize import optimize_vector from rpython.rlib.jit import PARAMETERS, ENABLE_ALL_OPTS from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.debug import debug_start, debug_stop, debug_print - ALL_OPTS = [('intbounds', OptIntBounds), ('rewrite', OptRewrite), ('virtualize', OptVirtualize), @@ -54,16 +52,9 @@ """ debug_start("jit-optimize") inputargs = compile_data.start_label.getarglist() - enable_opts = warmstate.enable_opts - if try_disabling_unroll: - if 'unroll' not in enable_opts: - return None - enable_opts = enable_opts.copy() - del enable_opts['unroll'] try: - metainterp_sd.logger_noopt.log_loop(inputargs, - compile_data.operations, + metainterp_sd.logger_noopt.log_loop(inputargs, compile_data.operations, memo=memo) if memo is None: memo = {} @@ -72,21 +63,6 @@ compile_data.enable_opts) return compile_data.optimize(metainterp_sd, jitdriver_sd, optimizations, unroll) - # XXX if unroll: - # XXX if not export_state and \ - # XXX ((warmstate.vec and jitdriver_sd.vec) \ - # XXX or warmstate.vec_all): - # XXX optimize_vector(metainterp_sd, jitdriver_sd, loop, - # XXX optimizations, inline_short_preamble, - # XXX start_state, warmstate) - # XXX else: - # XXX return optimize_unroll(metainterp_sd, jitdriver_sd, loop, - # XXX optimizations, inline_short_preamble, - # XXX start_state, export_state) - # XXX else: - # XXX optimizer = Optimizer(metainterp_sd, jitdriver_sd, loop, - # XXX optimizations) - # XXX optimizer.propagate_all_forward() finally: compile_data.forget_optimization_info() debug_stop("jit-optimize") diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -444,7 +444,14 @@ for _def in self.defs[arg]: yield _def[0] + def is_defined(self, arg): + return arg in self.defs + def definition(self, arg, node=None, argcell=None): + if arg.is_constant(): + return None + if arg.is_inputarg(): + return None def_chain = self.defs[arg] if len(def_chain) == 1: return def_chain[0][0] @@ -473,6 +480,8 @@ def depends_on_arg(self, arg, to, argcell=None): try: at = self.definition(arg, to, argcell) + if at is None: + return at.edge_to(to, arg) except KeyError: if not we_are_translated(): @@ -501,7 +510,9 @@ """ def __init__(self, loop): self.loop = loop - self.nodes = [ Node(op,i) for i,op in enumerate(loop.operations) ] + self.label = Node(loop.label, 0) + self.nodes = [ Node(op,i+1) for i,op in enumerate(loop.operations) ] + self.jump = Node(loop.jump, len(self.nodes)+1) self.invariant_vars = {} self.update_invariant_vars() self.memory_refs = {} @@ -515,8 +526,8 @@ return self.nodes[i] def update_invariant_vars(self): - label_op = self.nodes[0].getoperation() - jump_op = self.nodes[-1].getoperation() + label_op = self.label.getoperation() + jump_op = self.jump.getoperation() assert label_op.numargs() == jump_op.numargs() for i in range(label_op.numargs()): label_box = label_op.getarg(i) @@ -668,6 +679,8 @@ def guard_exit_dependence(self, guard_node, var, tracker): def_node = tracker.definition(var) + if def_node is None: + return for dep in def_node.provides(): if guard_node.is_before(dep.to) and dep.because_of(var): guard_node.edge_to(dep.to, var, label='guard_exit('+str(var)+')') @@ -690,7 +703,7 @@ # handle fail args if guard_op.getfailargs(): for arg in guard_op.getfailargs(): - if arg is None: + if arg is None or not tracker.is_defined(arg): continue try: for at in tracker.redefinitions(arg): @@ -728,10 +741,11 @@ # A trace is not entirely in SSA form. complex object # modification introduces WAR/WAW dependencies def_node = tracker.definition(arg) - for dep in def_node.provides(): - if dep.to != node: - dep.to.edge_to(node, argcell, label='war') - def_node.edge_to(node, argcell) + if def_node: + for dep in def_node.provides(): + if dep.to != node: + dep.to.edge_to(node, argcell, label='war') + def_node.edge_to(node, argcell) except KeyError: pass else: diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -261,14 +261,14 @@ # loop.operations = self._newoperations[:] - def propagate_all_forward(self, loop, user_code=False): + def propagate_all_forward(self, info, loop, user_code=False): """ strengthens the guards that protect an integral value """ # the guards are ordered. guards[i] is before guards[j] iff i < j self.collect_guard_information(loop) self.eliminate_guards(loop) # - assert len(loop.versions) == 1 - version = loop.versions[0] + assert len(info.versions) == 1 + version = info.versions[0] for i,op in enumerate(loop.operations): if not op.is_guard(): @@ -276,10 +276,10 @@ descr = op.getdescr() if descr and descr.loop_version(): assert isinstance(descr, ResumeGuardDescr) - loop.version_info.track(op, descr, version) + info.track(op, descr, version) if user_code: - self.eliminate_array_bound_checks(loop) + self.eliminate_array_bound_checks(info, loop) def emit_operation(self, op): self.renamer.rename(op) @@ -288,8 +288,7 @@ def operation_position(self): return len(self._newoperations) - def eliminate_array_bound_checks(self, loop): - info = loop.version_info + def eliminate_array_bound_checks(self, info, loop): info.mark() version = None self._newoperations = [] diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -6,6 +6,7 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, Dependency, IndexVar, MemoryRef, Node) +from rpython.jit.metainterp.optimizeopt.vector import TraceLoop from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.backend.llgraph.runner import ArrayDescr from rpython.rtyper.lltypesystem import rffi @@ -28,10 +29,9 @@ def parse_loop(self, ops): loop = self.parse(ops, postprocess=self.postprocess) token = JitCellToken() - loop.operations = [ResOperation(rop.LABEL, loop.inputargs, - descr=TargetToken(token))] + loop.operations - if loop.operations[-1].getopnum() == rop.JUMP: - loop.operations[-1].setdescr(token) + label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) + loop = TraceLoop(label, loop.operations[:-1], loop.operations[-1]) + loop.jump.setdescr(token) return loop def assert_edges(self, graph, edge_list, exceptions): @@ -39,13 +39,17 @@ adding None instead of a list of integers skips the test. This checks both if a dependency forward and backward exists. """ - assert len(edge_list) == len(graph.nodes) + assert len(edge_list) == len(graph.nodes) + 2 + edge_list = edge_list[1:-1] for idx,edges in enumerate(edge_list): if edges is None: continue node_a = graph.getnode(idx) dependencies = node_a.provides()[:] for idx_b in edges: + if idx_b == 0 or idx_b >= len(graph.nodes) + 2 -1: + continue + idx_b -= 1 node_b = graph.getnode(idx_b) dependency = node_a.getedge_to(node_b) if dependency is None and idx_b not in exceptions.setdefault(idx,[]): @@ -87,11 +91,17 @@ return graph def assert_independent(self, a, b): + # XXX + a -= 1 + b -= 1 a = self.last_graph.getnode(a) b = self.last_graph.getnode(b) assert a.independent(b), "{a} and {b} are dependent!".format(a=a,b=b) def assert_dependent(self, a, b): + # XXX + a -= 1 + b -= 1 a = self.last_graph.getnode(a) b = self.last_graph.getnode(b) assert not a.independent(b), "{a} and {b} are independent!".format(a=a,b=b) @@ -204,9 +214,6 @@ jump() # 4: """ graph = self.assert_dependencies(ops, full_check=True) - self.assert_independent(0,1) - self.assert_independent(0,2) - self.assert_independent(0,3) self.assert_dependent(1,2) self.assert_dependent(2,3) self.assert_dependent(1,3) @@ -231,9 +238,9 @@ def test_dependency_guard_2(self): ops = """ - [i1] # 0: 1,2?,3? + [i1] # 0: 1,2?,3 i2 = int_le(i1, 10) # 1: 2 - guard_true(i2) [i1] # 2: 3 + guard_true(i2) [i1] # 2: i3 = int_add(i1,1) # 3: 4 jump(i3) # 4: """ @@ -243,7 +250,7 @@ ops = """ [i1] # 0: 1,2?,3 i2 = int_lt(i1,10) # 1: 2 - guard_false(i2) [i1] # 2: 3 + guard_false(i2) [i1] # 2: i3 = int_add(i1,i1) # 3: 4 jump(i3) # 4: """ @@ -257,15 +264,12 @@ jump(i1) # 3: """ self.assert_dependencies(ops, full_check=True) - self.assert_dependent(0,1) - self.assert_dependent(0,2) - self.assert_dependent(0,3) def test_dependencies_1(self): ops=""" [i0, i1, i2] # 0: 1,3,6,7,11? i4 = int_gt(i1, 0) # 1: 2 - guard_true(i4) [] # 2: 3, 5, 11? + guard_true(i4) [] # 2: 5, 11? i6 = int_sub(i1, 1) # 3: 4 i8 = int_gt(i6, 0) # 4: 5 guard_false(i8) [] # 5: 10 @@ -279,7 +283,6 @@ self.assert_dependencies(ops, full_check=True) self.assert_independent(6, 2) self.assert_independent(6, 1) - self.assert_dependent(6, 0) def test_prevent_double_arg(self): ops=""" @@ -313,7 +316,7 @@ [p0, p1, i2] # 0: 1,2?,3?,4?,5? i3 = int_add(i2,1) # 1: 2 i4 = call_i(p0, i3, descr=nonwritedescr) # 2: 3,4,5? - guard_no_exception() [i2] # 3: 4?,5? + guard_no_exception() [i2] # 3: p2 = getarrayitem_gc_r(p1, i3, descr=arraydescr) # 4: 5 jump(p2, p1, i3) # 5: """ @@ -419,7 +422,6 @@ self.assert_dependencies(trace, full_check=True) def test_cyclic(self): - pass trace = """ [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6 guard_early_exit() [] # 1: 2,4,6,7 diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -1,15 +1,16 @@ import py from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop -from rpython.jit.metainterp.optimizeopt.util import equaloplists, Renamer -from rpython.jit.metainterp.optimizeopt.vectorize import (VecScheduleData, +from rpython.jit.metainterp.optimizeopt.util import equaloplists +from rpython.jit.metainterp.optimizeopt.renamer import Renamer +from rpython.jit.metainterp.optimizeopt.vec import (VecScheduleData, Pack, Pair, NotAProfitableLoop, VectorizingOptimizer, X86_CostModel, PackSet) from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph from rpython.jit.metainterp.optimizeopt.schedule import PackType from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_dependency import DependencyBaseTest -from rpython.jit.metainterp.optimizeopt.test.test_vectorize import (FakeMetaInterpStaticData, +from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, FakeJitDriverStaticData) from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.tool.oparser import parse as opparse @@ -42,8 +43,8 @@ def namespace(self): return { 'double': self.floatarraydescr, - 'float': self.singlefloatarraydescr, - 'long': self.intarraydescr, + 'float': self.float32arraydescr, + 'long': self.arraydescr, 'int': self.int32arraydescr, 'short': self.int16arraydescr, 'char': self.chararraydescr, @@ -77,8 +78,7 @@ loop = opparse(src, cpu=self.cpu, namespace=self.namespace()) if inc_label_jump: token = JitCellToken() - label = ResOperation(rop.LABEL, loop.inputargs, - None, descr=TargetToken(token)) + label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) loop.operations = [label] + loop.operations loop.graph = FakeDependencyGraph(loop) return loop @@ -138,19 +138,19 @@ class Test(SchedulerBaseTest, LLtypeMixin): def test_schedule_split_load(self): loop1 = self.parse(""" - i10 = raw_load(p0, i0, descr=float) - i11 = raw_load(p0, i1, descr=float) - i12 = raw_load(p0, i2, descr=float) - i13 = raw_load(p0, i3, descr=float) - i14 = raw_load(p0, i4, descr=float) - i15 = raw_load(p0, i5, descr=float) + f10 = raw_load_f(p0, i0, descr=float) + f11 = raw_load_f(p0, i1, descr=float) + f12 = raw_load_f(p0, i2, descr=float) + f13 = raw_load_f(p0, i3, descr=float) + f14 = raw_load_f(p0, i4, descr=float) + f15 = raw_load_f(p0, i5, descr=float) """) pack1 = self.pack(loop1, 0, 6, None, F32) loop2 = self.schedule(loop1, [pack1]) loop3 = self.parse(""" v10[i32|4] = vec_raw_load(p0, i0, 4, descr=float) - f10 = raw_load(p0, i4, descr=float) - f11 = raw_load(p0, i5, descr=float) + f10 = raw_load_f(p0, i4, descr=float) + f11 = raw_load_f(p0, i5, descr=float) """, False) self.assert_equal(loop2, loop3) 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 @@ -199,7 +199,10 @@ immut_ptrval = cpu.fielddescrof(PTROBJ_IMMUT, 'ptrval') arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed)) + int32arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.INT)) + int16arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.SHORT)) floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) + float32arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.SingleFloat)) arraydescr_tid = arraydescr.get_type_id() array = lltype.malloc(lltype.GcArray(lltype.Signed), 15, zero=True) arrayref = lltype.cast_opaque_ptr(llmemory.GCREF, array) @@ -207,7 +210,6 @@ array2ref = lltype.cast_opaque_ptr(llmemory.GCREF, array2) gcarraydescr = cpu.arraydescrof(lltype.GcArray(llmemory.GCREF)) gcarraydescr_tid = gcarraydescr.get_type_id() - floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) # a GcStruct not inheriting from OBJECT tpl = lltype.malloc(S, zero=True) @@ -403,6 +405,15 @@ failargs_limit = 1000 storedebug = None +class FakeWarmState(object): + vec = True # default is on + vec_all = False + vec_cost = 0 + def __init__(self, enable_opts): + self.enable_opts = enable_opts + +class FakeJitDriverStaticData(object): + vec = False class FakeMetaInterpStaticData(object): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -0,0 +1,1474 @@ +import py +import pytest + +from rpython.rlib.objectmodel import instantiate +from rpython.jit.metainterp.optimizeopt.test.test_util import (LLtypeMixin, + FakeMetaInterpStaticData, convert_old_style_to_targets, + FakeWarmState) +from rpython.jit.metainterp.optimizeopt.test.test_dependency import DependencyBaseTest +from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop +from rpython.jit.metainterp.optimizeopt import optimize_trace +import rpython.jit.metainterp.optimizeopt.optimizer as optimizeopt +import rpython.jit.metainterp.optimizeopt.virtualize as virtualize +from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph +from rpython.jit.metainterp.optimizeopt.vectorize import (VectorizingOptimizer, MemoryRef, + isomorphic, Pair, NotAVectorizeableLoop, NotAProfitableLoop, GuardStrengthenOpt, + CostModel) +from rpython.jit.metainterp.optimize import InvalidLoop +from rpython.jit.metainterp import compile +from rpython.jit.metainterp.resoperation import rop, ResOperation + +class FakeJitDriverStaticData(object): + vec=True + +class FakeCostModel(CostModel): + def __init__(self): + CostModel.__init__(self, 0, 16) + def record_cast_int(self): pass + def record_pack_savings(self, pack, times): pass + def record_vector_pack(self, box, index, count): pass + def record_vector_unpack(self, box, index, count): pass + def unpack_cost(self, op, index, count): pass + def savings_for_pack(self, pack, times): pass + def profitable(self): + return True + +ARCH_VEC_REG_SIZE = 16 + +class VecTestHelper(DependencyBaseTest): + + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + + jitdriver_sd = FakeJitDriverStaticData() + + def parse_loop(self, ops, add_label=True): + loop = self.parse(ops, postprocess=self.postprocess) + token = JitCellToken() + pre = [] + tt = TargetToken(token) + if add_label: + pre = [ResOperation(rop.LABEL, loop.inputargs, None, descr=tt)] + else: + for i,op in enumerate(loop.operations): + if op.getopnum() == rop.LABEL: + op.setdescr(tt) + loop.operations = pre + filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) + if loop.operations[-1].getopnum() == rop.JUMP: + loop.operations[-1].setdescr(token) + for op in loop.operations: + if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: + op.setdescr(compile.ResumeAtLoopHeaderDescr()) + return loop + + def assert_vectorize(self, loop, expected_loop, call_pure_results=None): + self._do_optimize_loop(loop, call_pure_results, export_state=True) + self.assert_equal(loop, expected_loop) + + def vectoroptimizer(self, loop): + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + jitdriver_sd = FakeJitDriverStaticData() + opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, loop, 0) + label_index = loop.find_first_index(rop.LABEL) + opt.orig_label_args = loop.operations[label_index].getarglist()[:] + return opt + + def vectoroptimizer_unrolled(self, loop, unroll_factor = -1): + loop.snapshot() + opt = self.vectoroptimizer(loop) + opt.linear_find_smallest_type(loop) + if unroll_factor == -1 and opt.smallest_type_bytes == 0: + raise NotAVectorizeableLoop() + if unroll_factor == -1: + unroll_factor = opt.get_unroll_count(ARCH_VEC_REG_SIZE) + print "" + print "unroll factor: ", unroll_factor, opt.smallest_type_bytes + if opt.loop.find_first_index(rop.GUARD_EARLY_EXIT) == -1: + idx = loop.find_first_index(rop.LABEL) + guard = ResOperation(rop.GUARD_EARLY_EXIT, [], None) + guard.setfailargs([]) + guard.setdescr(compile.ResumeAtLoopHeaderDescr()) + loop.operations.insert(idx+1, guard) + self.show_dot_graph(DependencyGraph(opt.loop), "original_" + self.test_name) + opt.analyse_index_calculations() + if opt.dependency_graph is not None: + cycle = opt.dependency_graph.cycles() + if cycle is not None: + print "CYCLE found %s" % cycle + self.show_dot_graph(opt.dependency_graph, "early_exit_" + self.test_name) + assert cycle is None + opt.schedule(False) + opt.unroll_loop_iterations(loop, unroll_factor) + opt.loop.operations = opt.get_newoperations() + self.debug_print_operations(opt.loop) + opt.clear_newoperations() + opt.dependency_graph = DependencyGraph(loop) + self.last_graph = opt.dependency_graph + self.show_dot_graph(self.last_graph, self.test_name) + return opt + + def init_packset(self, loop, unroll_factor = -1): + opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs() + return opt + + def extend_packset(self, loop, unroll_factor = -1): + opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs() + opt.extend_packset() + return opt + + def combine_packset(self, loop, unroll_factor = -1): + opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs() + opt.extend_packset() + opt.combine_packset() + return opt + + def schedule(self, loop, unroll_factor = -1, with_guard_opt=False): + opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.costmodel = FakeCostModel() + opt.find_adjacent_memory_refs() + opt.extend_packset() + opt.combine_packset() + opt.schedule(True) + if with_guard_opt: + gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) + gso.propagate_all_forward(opt.loop) + return opt + + def vectorize(self, loop, unroll_factor = -1): + opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs() + opt.extend_packset() + opt.combine_packset() + opt.costmodel.reset_savings() + opt.schedule(True) + if not opt.costmodel.profitable(): + raise NotAProfitableLoop() + gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) + gso.propagate_all_forward(opt.loop) + return opt + + def assert_unroll_loop_equals(self, loop, expected_loop, \ + unroll_factor = -1): + vectoroptimizer = self.vectoroptimizer_unrolled(loop, unroll_factor) + self.assert_equal(loop, expected_loop) + + def assert_pack(self, pack, indices): + assert len(pack.operations) == len(indices) + for op,i in zip(pack.operations, indices): + assert op.opidx == i + + def assert_has_pack_with(self, packset, opindices): + for pack in packset.packs: + for op,i in zip(pack.operations, opindices): + if op.opidx != i: + break + else: + # found a pack that points to the specified operations + break + else: + pytest.fail("could not find a packset that points to %s" % str(opindices)) + + def assert_packset_empty(self, packset, instr_count, exceptions): + for a,b in exceptions: + self.assert_packset_contains_pair(packset, a, b) + import itertools + combintations = set(itertools.product(range(instr_count), + range(instr_count))) + combintations -= set(exceptions) + for a,b in combintations: + self.assert_packset_not_contains_pair(packset, a, b) + + def assert_packset_not_contains_pair(self, packset, x, y): + for pack in packset.packs: + if pack.left.opidx == x and \ + pack.right.opidx == y: + pytest.fail("must not find packset with indices {x},{y}" \ + .format(x=x,y=y)) + + def assert_packset_contains_pair(self, packset, x, y): + for pack in packset.packs: + if isinstance(pack, Pair): + if pack.left.opidx == x and \ + pack.right.opidx == y: + break + else: + pytest.fail("can't find a pack set for indices {x},{y}" \ + .format(x=x,y=y)) + def assert_has_memory_ref_at(self, idx): + node = self.last_graph.nodes[idx] + assert node in self.last_graph.memory_refs, \ + "operation %s at pos %d has no memory ref!" % \ + (node.getoperation(), node.getindex()) + +class BaseTestVectorize(VecTestHelper): + + def test_vectorize_skip_impossible_1(self): + """ this trace does not contain a raw load / raw store from an array """ + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_le(i1, 10) + guard_true(i2) [] + jump(p0,i1) + """ + self.assert_vectorize(self.parse_loop(ops), self.parse_loop(ops)) + + def test_unroll_empty_stays_empty(self): + """ has no operations in this trace, thus it stays empty + after unrolling it 2 times """ + ops = """ + [] + jump() + """ + self.assert_unroll_loop_equals(self.parse_loop(ops), self.parse_loop(ops), 2) + + def test_vectorize_empty_with_early_exit(self): + ops = """ + [] + jump() + """ + try: + self.schedule(self.parse_loop(ops),1) + py.test.fail("empty loop with no memory references is not vectorizable") + except NotAVectorizeableLoop: + pass + + def test_unroll_empty_stays_empty_parameter(self): + """ same as test_unroll_empty_stays_empty but with a parameter """ + ops = """ + [i0] + jump(i0) + """ + self.assert_unroll_loop_equals(self.parse_loop(ops), self.parse_loop(ops), 2) + + def test_vect_pointer_fails(self): + """ it currently rejects pointer arrays """ + ops = """ + [p0,i0] + raw_load_r(p0,i0,descr=arraydescr2) + jump(p0,i0) + """ + self.assert_vectorize(self.parse_loop(ops), self.parse_loop(ops)) + + def test_load_primitive_python_list(self): + """ it currently rejects pointer arrays """ + ops = """ + [p0,i0] + i2 = getarrayitem_gc(p0,i0,descr=floatarraydescr) + i1 = int_add(i0,1) + i3 = getarrayitem_gc(p0,i1,descr=floatarraydescr) + i4 = int_add(i1,1) + jump(p0,i4) + """ + opt = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_add(i0,2) + i3 = vec_getarrayitem_gc(p0,i0,2,descr=floatarraydescr) + jump(p0,i2) + """ + vopt = self.vectorize(self.parse_loop(ops),0) + self.assert_equal(vopt.loop, self.parse_loop(opt)) + + def test_vect_unroll_char(self): + """ a 16 byte vector register can hold 16 bytes thus + it is unrolled 16 times. (it is the smallest type in the trace) """ + ops = """ + [p0,i0] + raw_load_i(p0,i0,descr=chararraydescr) + jump(p0,i0) + """ + opt_ops = """ + [p0,i0] + {} + jump(p0,i0) + """.format(('\n' + ' ' *8).join(['raw_load_i(p0,i0,descr=chararraydescr)'] * 16)) + self.assert_unroll_loop_equals(self.parse_loop(ops), self.parse_loop(opt_ops)) + + def test_unroll_vector_addition(self): + """ a more complex trace doing vector addition (smallest type is float + 8 byte) """ + ops = """ + [p0,p1,p2,i0] + i1 = raw_load_i(p1, i0, descr=floatarraydescr) + i2 = raw_load_i(p2, i0, descr=floatarraydescr) + i3 = int_add(i1,i2) + raw_store(p0, i0, i3, descr=floatarraydescr) + i4 = int_add(i0, 1) + i5 = int_le(i4, 10) + guard_true(i5) [] + jump(p0,p1,p2,i4) + """ + opt_ops = """ + [p0,p1,p2,i0] + i4 = int_add(i0, 1) + i5 = int_le(i4, 10) + guard_true(i5) [] + i1 = raw_load_i(p1, i0, descr=floatarraydescr) + i2 = raw_load_i(p2, i0, descr=floatarraydescr) + i3 = int_add(i1,i2) + raw_store(p0, i0, i3, descr=floatarraydescr) + i9 = int_add(i4, 1) + i10 = int_le(i9, 10) + guard_true(i10) [] + i6 = raw_load_i(p1, i4, descr=floatarraydescr) + i7 = raw_load_i(p2, i4, descr=floatarraydescr) + i8 = int_add(i6,i7) + raw_store(p0, i4, i8, descr=floatarraydescr) + jump(p0,p1,p2,i9) + """ + self.assert_unroll_loop_equals(self.parse_loop(ops), self.parse_loop(opt_ops), 1) + + def test_estimate_unroll_factor_smallest_byte_zero(self): + ops = """ + [p0,i0] + raw_load_i(p0,i0,descr=arraydescr) + jump(p0,i0) + """ + vopt = self.vectoroptimizer(self.parse_loop(ops)) + assert 0 == vopt.smallest_type_bytes + assert 0 == vopt.get_unroll_count(ARCH_VEC_REG_SIZE) + + def test_array_operation_indices_not_unrolled(self): + ops = """ + [p0,i0] + raw_load_i(p0,i0,descr=arraydescr) + jump(p0,i0) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + assert len(vopt.dependency_graph.memory_refs) == 1 + self.assert_has_memory_ref_at(1) + + def test_array_operation_indices_unrolled_1(self): + ops = """ + [p0,i0] + raw_load_i(p0,i0,descr=chararraydescr) + jump(p0,i0) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) + assert len(vopt.dependency_graph.memory_refs) == 2 + self.assert_has_memory_ref_at(1) + self.assert_has_memory_ref_at(2) + + def test_array_operation_indices_unrolled_2(self): + ops = """ + [p0,i0,i1] + i3 = raw_load_i(p0,i0,descr=chararraydescr) + i4 = raw_load_i(p0,i1,descr=chararraydescr) + jump(p0,i3,i4) + """ + loop = self.parse_loop(ops) + vopt = self.vectoroptimizer_unrolled(loop,0) + assert len(vopt.dependency_graph.memory_refs) == 2 + self.assert_has_memory_ref_at(1) + self.assert_has_memory_ref_at(2) + # + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) + assert len(vopt.dependency_graph.memory_refs) == 4 + for i in [1,2,3,4]: + self.assert_has_memory_ref_at(i) + # + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),3) + assert len(vopt.dependency_graph.memory_refs) == 8 + for i in [1,2,3,4,5,6,7,8]: + self.assert_has_memory_ref_at(i) + + def test_array_memory_ref_adjacent_1(self): + ops = """ + [p0,i0] + i3 = raw_load_i(p0,i0,descr=chararraydescr) + i1 = int_add(i0,1) + jump(p0,i1) + """ + loop = self.parse_loop(ops) + vopt = self.vectoroptimizer_unrolled(loop,1) + vopt.find_adjacent_memory_refs() + assert len(vopt.dependency_graph.memory_refs) == 2 + + mref1 = self.getmemref(loop.find_first_index(rop.RAW_LOAD)) + mref3 = self.getmemref(loop.find_first_index(rop.RAW_LOAD,1)) + assert isinstance(mref1, MemoryRef) + assert isinstance(mref3, MemoryRef) + + assert mref1.is_adjacent_to(mref3) + assert mref3.is_adjacent_to(mref1) + + def test_array_memory_ref_1(self): + ops = """ + [p0,i0] + i3 = raw_load_i(p0,i0,descr=chararraydescr) + jump(p0,i0) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(1) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 1 + assert mref1.index_var.constant == 0 + + def test_array_memory_ref_2(self): + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i3 = raw_load_i(p0,i1,descr=chararraydescr) + jump(p0,i1) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(2) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 1 + assert mref1.index_var.constant == 1 + + def test_array_memory_ref_sub_index(self): + ops = """ + [p0,i0] + i1 = int_sub(i0,1) + i3 = raw_load_i(p0,i1,descr=chararraydescr) + jump(p0,i1) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(2) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 1 + assert mref1.index_var.constant == -1 + + def test_array_memory_ref_add_mul_index(self): + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_mul(i1,3) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + jump(p0,i1) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(3) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 3 + assert mref1.index_var.constant == 3 + + def test_array_memory_ref_add_mul_index_interleaved(self): + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_mul(i1,3) + i3 = int_add(i2,5) + i4 = int_mul(i3,6) + i5 = raw_load_i(p0,i4,descr=chararraydescr) + jump(p0,i4) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(5) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 18 + assert mref1.index_var.constant == 48 + + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_mul(i1,3) + i3 = int_add(i2,5) + i4 = int_mul(i3,6) + i5 = int_add(i4,30) + i6 = int_mul(i5,57) + i7 = raw_load_i(p0,i6,descr=chararraydescr) + jump(p0,i6) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(7) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 1026 + assert mref1.index_var.coefficient_div == 1 + assert mref1.index_var.constant == 57*(30) + 57*6*(5) + 57*6*3*(1) + + def test_array_memory_ref_sub_mul_index_interleaved(self): + ops = """ + [p0,i0] + i1 = int_add(i0,1) + i2 = int_mul(i1,3) + i3 = int_sub(i2,3) + i4 = int_mul(i3,2) + i5 = raw_load_i(p0,i4,descr=chararraydescr) + jump(p0,i4) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref1 = self.getmemref(5) + assert isinstance(mref1, MemoryRef) + assert mref1.index_var.coefficient_mul == 6 + assert mref1.index_var.coefficient_div == 1 + assert mref1.index_var.constant == 0 + + def test_array_memory_ref_not_adjacent_1(self): + ops = """ + [p0,i0,i4] + i3 = raw_load_i(p0,i0,descr=chararraydescr) + i1 = int_add(i0,1) + i5 = raw_load_i(p0,i4,descr=chararraydescr) + i6 = int_add(i4,1) + jump(p0,i1,i6) + """ + loop = self.parse_loop(ops) + vopt = self.vectoroptimizer_unrolled(loop,1) + vopt.find_adjacent_memory_refs() + + f = lambda x: loop.find_first_index(rop.RAW_LOAD, x) + indices = [f(0),f(1),f(2),f(3)] + for i in indices: + self.assert_has_memory_ref_at(i) + assert len(vopt.dependency_graph.memory_refs) == 4 + + mref1, mref3, mref5, mref7 = [self.getmemref(i) for i in indices] + assert isinstance(mref1, MemoryRef) + assert isinstance(mref3, MemoryRef) + assert isinstance(mref5, MemoryRef) + assert isinstance(mref7, MemoryRef) + + self.assert_memory_ref_adjacent(mref1, mref5) + self.assert_memory_ref_not_adjacent(mref1, mref3) + self.assert_memory_ref_not_adjacent(mref1, mref7) + self.assert_memory_ref_adjacent(mref3, mref7) + assert mref1.is_adjacent_after(mref5) + + def test_array_memory_ref_div(self): + ops = """ + [p0,i0] + i1 = int_floordiv(i0,2) + i2 = int_floordiv(i1,8) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + jump(p0,i2) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref = self.getmemref(3) + assert mref.index_var.coefficient_div == 16 + ops = """ + [p0,i0] + i1 = int_add(i0,8) + i2 = uint_floordiv(i1,2) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + jump(p0,i2) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref = self.getmemref(3) + assert mref.index_var.coefficient_div == 2 + assert mref.index_var.constant == 4 + ops = """ + [p0,i0] + i1 = int_add(i0,8) + i2 = int_floordiv(i1,2) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + i4 = int_add(i0,4) + i5 = int_mul(i4,2) + i6 = raw_load_i(p0,i5,descr=chararraydescr) + jump(p0,i2) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref = self.getmemref(5) + mref2 = self.getmemref(6) + + self.assert_memory_ref_not_adjacent(mref, mref2) + assert mref != mref2 + + def test_array_memory_ref_diff_calc_but_equal(self): + ops = """ + [p0,i0] + i1 = int_add(i0,4) + i2 = int_mul(i1,2) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + i4 = int_add(i0,2) + i5 = int_mul(i4,2) + i6 = int_add(i5,4) + i7 = raw_load_i(p0,i6,descr=chararraydescr) + jump(p0,i2) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref = self.getmemref(6) + mref2 = self.getmemref(7) + + self.assert_memory_ref_not_adjacent(mref, mref2) + assert mref == mref2 + + def test_array_memory_ref_diff_not_equal(self): + ops = """ + [p0,i0] + i1 = int_add(i0,4) + i2 = int_floordiv(i1,2) + i3 = raw_load_i(p0,i2,descr=chararraydescr) + i4 = int_add(i0,2) + i5 = int_mul(i4,2) + i6 = int_add(i5,4) + i7 = raw_load_i(p0,i6,descr=chararraydescr) + jump(p0,i2) + """ + vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs() + mref = self.getmemref(6) + mref2 = self.getmemref(7) + + self.assert_memory_ref_not_adjacent(mref, mref2) + assert mref != mref2 + + def test_packset_init_simple(self): + ops = """ + [p0,i0] + i3 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i1 = int_add(i0, 1) + i2 = int_le(i1, 16) + guard_true(i2) [p0, i0] + jump(p0,i1) + """ + loop = self.parse_loop(ops) + vopt = self.init_packset(loop,1) + self.assert_independent(4,8) + assert vopt.packset is not None + assert len(vopt.dependency_graph.memory_refs) == 2 + assert len(vopt.packset.packs) == 1 + + def test_packset_init_raw_load_not_adjacent_and_adjacent(self): + ops = """ + [p0,i0] + i3 = raw_load_i(p0, i0, descr=chararraydescr) + jump(p0,i0) + """ + loop = self.parse_loop(ops) + vopt = self.init_packset(loop,3) + assert len(vopt.dependency_graph.memory_refs) == 4 + assert len(vopt.packset.packs) == 0 + ops = """ + [p0,i0] + i2 = int_add(i0,1) + raw_load_i(p0, i2, descr=chararraydescr) + jump(p0,i2) + """ + loop = self.parse_loop(ops) + vopt = self.init_packset(loop,3) + assert len(vopt.dependency_graph.memory_refs) == 4 + assert len(vopt.packset.packs) == 3 + for i in range(3): + x = (i+1)*2 + y = x + 2 + self.assert_independent(x,y) + self.assert_packset_contains_pair(vopt.packset, x,y) + + def test_packset_init_2(self): + ops = """ + [p0,i0] + i1 = int_add(i0, 1) + i2 = int_le(i1, 16) + guard_true(i2) [p0, i0] + i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + jump(p0,i1) + """ + loop = self.parse_loop(ops) + vopt = self.init_packset(loop,15) + assert len(vopt.dependency_graph.memory_refs) == 16 + assert len(vopt.packset.packs) == 15 + # assure that memory refs are not adjacent for all + for i in range(15): + for j in range(15): + try: + if i-4 == j or i+4 == j: + mref1 = self.getmemref(i) + mref2 = self.getmemref(j) + assert mref1.is_adjacent_to(mref2) + else: + mref1 = self.getmemref(i) + mref2 = self.getmemref(j) + assert not mref1.is_adjacent_to(mref2) + except KeyError: + pass + for i in range(15): + x = (i+1)*4 + y = x + 4 + self.assert_independent(x,y) + self.assert_packset_contains_pair(vopt.packset, x, y) + + def test_isomorphic_operations(self): + ops_src = """ + [p1,p0,i0] + i3 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i1 = int_add(i0, 1) + i2 = int_le(i1, 16) + i4 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i5 = getarrayitem_raw(p1, i1, descr=floatarraydescr) + i6 = getarrayitem_raw(p0, i1, descr=floatarraydescr) + guard_true(i2) [p0, i0] + jump(p1,p0,i1) + """ + loop = self.parse_loop(ops_src) + ops = loop.operations + assert isomorphic(ops[1], ops[4]) + assert not isomorphic(ops[0], ops[1]) + assert not isomorphic(ops[0], ops[5]) + # TODO strong assumptions do hold here? + #assert not isomorphic(ops[4], ops[5]) + #assert not isomorphic(ops[5], ops[6]) + #assert not isomorphic(ops[4], ops[6]) + #assert not isomorphic(ops[1], ops[6]) + + def test_packset_extend_simple(self): + ops = """ + [p0,i0] + i1 = int_add(i0, 1) + i2 = int_le(i1, 16) + guard_true(i2) [p0, i0] + i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i4 = int_add(i3, 1) + jump(p0,i1) + """ + loop = self.parse_loop(ops) + vopt = self.extend_packset(loop,1) + assert len(vopt.dependency_graph.memory_refs) == 2 + self.assert_independent(5,10) + assert len(vopt.packset.packs) == 2 + self.assert_packset_empty(vopt.packset, len(loop.operations), + [(5,10), (4,9)]) + + def test_packset_extend_load_modify_store(self): + ops = """ + [p0,i0] + guard_early_exit() [] + i1 = int_add(i0, 1) + i2 = int_le(i1, 16) + guard_true(i2) [p0, i0] + i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i4 = int_mul(i3, 2) + setarrayitem_raw(p0, i1, i4, descr=chararraydescr) + jump(p0,i1) + """ + loop = self.parse_loop(ops) + vopt = self.extend_packset(loop,1) + assert len(vopt.dependency_graph.memory_refs) == 4 + self.assert_independent(4,10) + self.assert_independent(5,11) + self.assert_independent(6,12) + assert len(vopt.packset.packs) == 3 + self.assert_packset_empty(vopt.packset, len(loop.operations), + [(6,12), (5,11), (4,10)]) + + @pytest.mark.parametrize("descr,packs,packidx", + [('char',1, [(0,(2,4,6,8))]), + ('float',2, [(0,(2,4)),(1,(6,8))]), + ('int',2, [(0,(2,4)),(1,(6,8))]), + ('singlefloat',1,[(0,(2,4,6,8))])]) + def test_packset_combine_simple(self,descr,packs,packidx): + ops = """ + [p0,i0] + i3 = getarrayitem_raw(p0, i0, descr={descr}arraydescr) + i1 = int_add(i0,1) + jump(p0,i1) + """.format(descr=descr) + loop = self.parse_loop(ops) + vopt = self.combine_packset(loop,3) + assert len(vopt.dependency_graph.memory_refs) == 4 + assert len(vopt.packset.packs) == packs + for i,t in packidx: + self.assert_pack(vopt.packset.packs[i], t) + + @pytest.mark.parametrize("descr,stride,packs,suffix", + [('char',1,1,'_i'),('float',8,4,'_f'),('int',8,4,'_i'),('float32',4,2,'_i')]) + def test_packset_combine_2_loads_in_trace(self, descr, stride,packs): + ops = """ + [p0,i0] + i3 = raw_load{suffix}(p0, i0, descr={type}arraydescr) + i1 = int_add(i0,{stride}) + i4 = raw_load{suffix}(p0, i1, descr={type}arraydescr) + i2 = int_add(i1,{stride}) + jump(p0,i2) + """.format(type=descr,stride=stride,suffix=suffix) + loop = self.parse_loop(ops) + vopt = self.combine_packset(loop,3) + assert len(vopt.dependency_graph.memory_refs) == 8 + assert len(vopt.packset.packs) == packs + + def test_packset_combine_no_candidates_packset_empty(self): + ops = """ + [] + jump() + """ + try: + self.combine_packset(self.parse_loop(ops),15) + pytest.fail("combine should raise an exception if no pack " + "statements are present") + except NotAVectorizeableLoop: + pass + + ops = """ + [p0,i0] + i3 = getarrayitem_raw(p0, i0, descr=floatarraydescr) + jump(p0,i3) + """ + try: + loop = self.parse_loop(ops) + self.combine_packset(loop,15) + except NotAVectorizeableLoop: + pass + + @pytest.mark.parametrize("op,descr,stride", + [('int_add','char',1), + ('int_sub','char',1), + ('int_mul','char',1), + ('float_add','float',8), + ('float_sub','float',8), + ('float_mul','float',8), + ('float_add','singlefloat',4), + ('float_sub','singlefloat',4), + ('float_mul','singlefloat',4), + ('int_add','int',8), + ('int_sub','int',8), + ('int_mul','int',8), + ]) + def test_packset_vector_operation(self, op, descr, stride): + ops = """ + [p0,p1,p2,i0] + guard_early_exit() [] + i1 = int_add(i0, {stride}) + i10 = int_le(i1, 128) + guard_true(i10) [] + i2 = raw_load{suffix}(p0, i0, descr={descr}arraydescr) + i3 = raw_load{suffix}(p1, i0, descr={descr}arraydescr) + i4 = {op}(i2,i3) + raw_store(p2, i0, i4, descr={descr}arraydescr) + jump(p0,p1,p2,i1) + """.format(op=op,descr=descr,stride=stride) + loop = self.parse_loop(ops) + vopt = self.combine_packset(loop,3) + assert len(vopt.dependency_graph.memory_refs) == 12 + if stride == 8: + assert len(vopt.packset.packs) == 8 + else: + assert len(vopt.packset.packs) == 4 + + for opindices in [(5,12,19,26),(6,13,20,27), + (7,14,21,28),(4,11,18,25)]: + self.assert_has_pack_with(vopt.packset, opindices) + + @pytest.mark.parametrize('op,descr,stride', + [('float_add','float',8), + ('float_sub','float',8), + ('float_mul','float',8), + ('int_add','int',8), + ('int_sub','int',8), + ]) + def test_schedule_vector_operation(self, op, descr, stride): + ops = """ + [p0,p1,p2,i0] # 0 + guard_early_exit() [] + i10 = int_le(i0, 128) # 1, 8, 15, 22 + guard_true(i10) [p0,p1,p2,i0] # 2, 9, 16, 23 + i2 = getarrayitem_raw(p0, i0, descr={descr}arraydescr) # 3, 10, 17, 24 + i3 = getarrayitem_raw(p1, i0, descr={descr}arraydescr) # 4, 11, 18, 25 + i4 = {op}(i2,i3) # 5, 12, 19, 26 + setarrayitem_raw(p2, i0, i4, descr={descr}arraydescr) # 6, 13, 20, 27 + i1 = int_add(i0, {stride}) # 7, 14, 21, 28 + jump(p0,p1,p2,i1) # 29 + """.format(op=op,descr=descr,stride=1) # stride getarray is always 1 + vops = """ + [p0,p1,p2,i0] + i10 = int_le(i0, 128) + guard_true(i10) [] + i1 = int_add(i0, {stride}) + i11 = int_le(i1, 128) + guard_true(i11) [] + i12 = int_add(i1, {stride}) + v1 = vec_getarrayitem_raw(p0, i0, 2, descr={descr}arraydescr) + v2 = vec_getarrayitem_raw(p1, i0, 2, descr={descr}arraydescr) + v3 = {op}(v1,v2) + vec_setarrayitem_raw(p2, i0, v3, descr={descr}arraydescr) + jump(p0,p1,p2,i12) + """.format(op='vec_'+op,descr=descr,stride=1) + loop = self.parse_loop(ops) + vopt = self.schedule(loop, 1) + self.assert_equal(loop, self.parse_loop(vops)) + + def test_vschedule_trace_1(self): + ops = """ + [i0, i1, i2, i3, i4] + guard_early_exit() [] + i6 = int_mul(i0, 8) + i7 = raw_load(i2, i6, descr=arraydescr) + i8 = raw_load(i3, i6, descr=arraydescr) + i9 = int_add(i7, i8) + raw_store(i4, i6, i9, descr=arraydescr) + i11 = int_add(i0, 1) + i12 = int_lt(i11, i1) + guard_true(i12) [i4, i3, i2, i1, i11] + jump(i11, i1, i2, i3, i4) + """ + opt=""" + [i0, i1, i2, i3, i4] + i11 = int_add(i0, 1) + i6 = int_mul(i0, 8) + i12 = int_lt(i11, i1) + guard_true(i12) [] + i13 = int_add(i11, 1) + i14 = int_mul(i11, 8) + i18 = int_lt(i13, i1) + guard_true(i18) [] + v19 = vec_raw_load(i2, i6, 2, descr=arraydescr) + v20 = vec_raw_load(i3, i6, 2, descr=arraydescr) + v21 = vec_int_add(v19, v20) + vec_raw_store(i4, i6, v21, descr=arraydescr) + jump(i13, i1, i2, i3, i4) + """ + vopt = self.schedule(self.parse_loop(ops),1) + self.assert_equal(vopt.loop, self.parse_loop(opt)) + + def test_collapse_index_guard_1(self): + ops = """ + [p0,i0] + guard_early_exit() [p0,i0] + i1 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i2 = int_add(i0, 1) + i3 = int_lt(i2, 102) + guard_true(i3) [p0,i0] + jump(p0,i2) + """ + dead_code = '\n '.join([ + "i{t1} = int_add(i0,{i})\n i{s} = int_lt(i{t1}, 102)".format( + i=i+2, t1=i+201, t=i+200, s=i+20) + for i in range(0,14)]) + opt=""" + [p0,i0] + i200 = int_add(i0, 1) + i400 = int_lt(i200, 102) + i2 = int_add(i0, 16) + i3 = int_lt(i2, 102) + guard_true(i3) [p0,i0] + {dead_code} + i500 = int_add(i0, 16) + i501 = int_lt(i2, 102) + i1 = vec_getarrayitem_raw(p0, i0, 16, descr=chararraydescr) + jump(p0,i2) + """.format(dead_code=dead_code) + vopt = self.schedule(self.parse_loop(ops),15,with_guard_opt=True) + self.assert_equal(vopt.loop, self.parse_loop(opt)) + + def test_too_small_vector(self): + ops = """ + [p0,i0] + guard_early_exit() [p0,i0] + i1 = getarrayitem_raw(p0, 0, descr=chararraydescr) # constant index + i2 = getarrayitem_raw(p0, 1, descr=chararraydescr) # constant index + i4 = int_add(i1, i2) + i3 = int_add(i0,1) + i5 = int_lt(i3, 10) + guard_true(i5) [p0, i0] + jump(p0,i1) + """ + try: + self.vectorize(self.parse_loop(ops)) + py.test.fail("loop is not vectorizable") + except NotAVectorizeableLoop: + pass + + def test_constant_expansion(self): + ops = """ + [p0,i0] + guard_early_exit() [p0,i0] + i1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) + i4 = int_sub(i1, 42) + i3 = int_add(i0,1) + i5 = int_lt(i3, 10) + guard_true(i5) [p0, i0] + jump(p0,i3) + """ + opt=""" + [p0,i0] + label(p0,i0) + v3 = vec_int_expand(42, 2) + label(p0,i0,v3) + i20 = int_add(i0, 1) + i30 = int_lt(i20, 10) + i2 = int_add(i0, 2) + i3 = int_lt(i2, 10) + guard_true(i3) [p0,i0] + i4 = int_add(i0, 2) + i5 = int_lt(i2, 10) + v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr) + v2 = vec_int_sub(v1, v3) + jump(p0,i2,v3) + """ + vopt = self.vectorize(self.parse_loop(ops),1) + self.assert_equal(vopt.loop, self.parse_loop(opt,add_label=False)) + + def test_variable_expansion(self): + ops = """ + [p0,i0,f3] + guard_early_exit() [p0,i0] + f1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) + f4 = int_add(f1, f3) + i3 = int_add(i0,1) + i5 = int_lt(i3, 10) + guard_true(i5) [p0, i0] + jump(p0,i3,f3) + """ + opt=""" + [p0,i0,f3] + label(p0,i0,f3) + v3 = vec_float_expand(f3,2) + label(p0,i0,f3,v3) + i20 = int_add(i0, 1) + i30 = int_lt(i20, 10) + i2 = int_add(i0, 2) + i3 = int_lt(i2, 10) + guard_true(i3) [p0,i0,f3] + i4 = int_add(i0, 2) + i5 = int_lt(i2, 10) + v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr) + v2 = vec_int_add(v1, v3) + jump(p0,i2,f3,v3) + """ + vopt = self.vectorize(self.parse_loop(ops),1) + self.assert_equal(vopt.loop, self.parse_loop(opt, add_label=False)) + + def test_accumulate_basic(self): + trace = """ + [p0, i0, f0] + guard_early_exit() [p0, i0, f0] + f1 = raw_load(p0, i0, descr=floatarraydescr) + f2 = float_add(f0, f1) + i1 = int_add(i0, 8) + i2 = int_lt(i1, 100) + guard_false(i2) [p0, i0, f2] + jump(p0, i1, f2) + """ + trace_opt = """ + [p0, i0, v2[f64|2]] + i1 = int_add(i0, 16) + i2 = int_lt(i1, 100) + guard_false(i2) [p0, i0, v[f64|2]] + i10 = int_add(i0, 16) + i20 = int_lt(i10, 100) + v1[f64|2] = vec_raw_load(p0, i0, 2, descr=floatarraydescr) + v3[f64|2] = vec_float_add(v2[f64|2], v1[f64|2]) + jump(p0, i1, v3[f64|2]) + """ + opt = self.vectorize(self.parse_loop(trace)) + assert len(opt.packset.accum_vars) == 1 + assert opt.loop.inputargs[2] in opt.packset.accum_vars + self.debug_print_operations(opt.loop) + + def test_element_f45_in_guard_failargs(self): + ops = """ + [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] + guard_early_exit() [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41] + f45 = raw_load(i21, i44, descr=floatarraydescr) + guard_not_invalidated() [p38, p12, p9, p14, f45, p39, i37, i44, f35, i40, p42, i43, None, i28, p36, i41] + i46 = int_add(i44, 8) + f47 = raw_load(i4, i41, descr=floatarraydescr) + i48 = int_add(i41, 8) + f49 = float_add(f45, f47) + raw_store(i0, i37, f49, descr=floatarraydescr) + i50 = int_add(i28, 1) + i51 = int_add(i37, 8) + i52 = int_ge(i50, i18) + guard_false(i52) [p38, p12, p9, p14, i48, i46, f47, i51, i50, f45, p39, None, None, None, i40, p42, i43, None, None, p36, None] + jump(p36, i50, p9, i51, p14, f45, p12, p38, f47, p39, i40, i48, p42, i43, i46, i21, i4, i0, i18) + """ + opt = """ + [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] + guard_not_invalidated() [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41] + i50 = int_add(i28, 1) + i48 = int_add(i41, 8) + i51 = int_add(i37, 8) + i54 = int_add(i41, 16) + i46 = int_add(i44, 8) + i56 = int_add(i37, 16) + i52 = int_ge(i50, i18) + i637 = int_add(i28, 2) + i638 = int_ge(i637, i18) + guard_false(i638) [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] + i55 = int_add(i44, 16) + i629 = int_add(i28, 2) + i57 = int_ge(i637, i18) + v61 = vec_raw_load(i21, i44, 2, descr=floatarraydescr) + v62 = vec_raw_load(i4, i41, 2, descr=floatarraydescr) + v63 = vec_float_add(v61, v62) + vec_raw_store(i0, i37, v63, descr=floatarraydescr) + f100 = vec_float_unpack(v61, 1, 1) + f101 = vec_float_unpack(v62, 1, 1) + jump(p36, i637, p9, i56, p14, f100, p12, p38, f101, p39, i40, i54, p42, i43, i55, i21, i4, i0, i18) + """ + vopt = self.vectorize(self.parse_loop(ops)) + self.assert_equal(vopt.loop, self.parse_loop(opt)) + + def test_shrink_vector_size(self): + ops = """ + [p0,p1,i1] + guard_early_exit() [] + f1 = getarrayitem_raw(p0, i1, descr=floatarraydescr) + i2 = cast_float_to_singlefloat(f1) + setarrayitem_raw(p1, i1, i2, descr=singlefloatarraydescr) + i3 = int_add(i1, 1) + i4 = int_ge(i3, 36) + guard_false(i4) [] + jump(p0, p1, i3) + """ + opt = """ + [p0, p1, i1] + i3 = int_add(i1, 1) + i4 = int_ge(i3, 36) + i50 = int_add(i1, 4) + i51 = int_ge(i50, 36) + guard_false(i51) [p0, p1, i1] + i5 = int_add(i1, 2) + i8 = int_ge(i5, 36) + i6 = int_add(i1, 3) + i11 = int_ge(i6, 36) + i7 = int_add(i1, 4) + i14 = int_ge(i50, 36) + v17 = vec_getarrayitem_raw(p0, i1, 2, descr=floatarraydescr) + v19 = vec_cast_float_to_singlefloat(v17) + v18 = vec_getarrayitem_raw(p0, i5, 2, descr=floatarraydescr) + v20 = vec_cast_float_to_singlefloat(v18) + v21 = vec_float_pack(v19, v20, 2, 2) + vec_setarrayitem_raw(p1, i1, v21, descr=singlefloatarraydescr) + jump(p0, p1, i50) + """ From noreply at buildbot.pypy.org Thu Sep 10 19:15:01 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 10 Sep 2015 19:15:01 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: finished the new dependency model. label and jump are tracked no more. this greatly reduces the edge count in the graph Message-ID: <20150910171501.F19F91C0362@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79586:50d4f3bd716c Date: 2015-09-10 19:15 +0200 http://bitbucket.org/pypy/pypy/changeset/50d4f3bd716c/ Log: finished the new dependency model. label and jump are tracked no more. this greatly reduces the edge count in the graph diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -450,32 +450,30 @@ def definition(self, arg, node=None, argcell=None): if arg.is_constant(): return None - if arg.is_inputarg(): + def_chain = self.defs.get(arg,None) + if not def_chain: return None - def_chain = self.defs[arg] - if len(def_chain) == 1: - return def_chain[0][0] + if not argcell: + return def_chain[-1][0] else: - if not argcell: - return def_chain[-1][0] - else: - assert node is not None - i = len(def_chain)-1 - try: - mref = node.memory_ref - while i >= 0: - def_node = def_chain[i][0] - oref = def_node.memory_ref - if oref is not None and mref.alias(oref): - return def_node - elif oref is None: - return def_node - i -= 1 - except KeyError: - # when a key error is raised, this means - # no information is available, safe default - pass - return def_chain[-1][0] + assert node is not None + i = len(def_chain)-1 + try: + mref = node.memory_ref + while i >= 0: + def_node = def_chain[i][0] + oref = def_node.memory_ref + if oref is not None and mref.alias(oref): + return def_node + elif oref is None: + return def_node + i -= 1 + return None + except KeyError: + # when a key error is raised, this means + # no information is available, safe default + pass + return def_chain[-1][0] def depends_on_arg(self, arg, to, argcell=None): try: @@ -703,7 +701,9 @@ # handle fail args if guard_op.getfailargs(): for arg in guard_op.getfailargs(): - if arg is None or not tracker.is_defined(arg): + if arg is None: + continue + if not tracker.is_defined(arg): continue try: for at in tracker.redefinitions(arg): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -333,7 +333,7 @@ """ self.assert_dependencies(ops, full_check=True) - def test_not_forced(self): + def test_call_not_forced_exception(self): ops=""" [p0, p1, i2, i5] # 0: 1,2,4?,5,6 i4 = call_i(i5, i2, descr=nonwritedescr) # 1: 2,4,6 @@ -344,8 +344,8 @@ jump(p2, p1, i2, i5) # 6: """ self.assert_dependencies(ops, full_check=True) + assert self.last_graph.nodes[1].priority == 100 assert self.last_graph.nodes[2].priority == 100 - assert self.last_graph.nodes[3].priority == 100 def test_setarrayitem_dependency(self): ops=""" @@ -368,7 +368,6 @@ """ self.assert_dependencies(ops, full_check=True) self.assert_dependent(1,2) - self.assert_dependent(0,3) def test_setarrayitem_dont_depend_with_memref_info(self): ops=""" @@ -424,7 +423,7 @@ def test_cyclic(self): trace = """ [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6 - guard_early_exit() [] # 1: 2,4,6,7 + guard_early_exit() [] # 1: p13 = getfield_gc_r(p9) # 2: 3,5,6 guard_nonnull(p13) [] # 3: 5,6 i14 = getfield_gc_i(p9) # 4: 6 From noreply at buildbot.pypy.org Thu Sep 10 20:38:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 10 Sep 2015 20:38:43 +0200 (CEST) Subject: [pypy-commit] pypy default: fix some more Message-ID: <20150910183843.840971C1342@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79587:38bdf715cb93 Date: 2015-09-10 14:48 +0200 http://bitbucket.org/pypy/pypy/changeset/38bdf715cb93/ Log: fix some more diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -414,11 +414,7 @@ guard_not_invalidated(descr=...) p163 = force_token() p164 = force_token() - p165 = getarrayitem_gc(p67, 0, descr=) - guard_value(p165, ConstPtr(ptr70), descr=...) - p166 = getfield_gc(p165, descr=) - guard_value(p166, ConstPtr(ptr72), descr=...) - p167 = call(ConstClass(_ll_0_alloc_with_del___), descr=) + p167 = call_r(ConstClass(_ll_0_alloc_with_del___), descr=) guard_no_exception(descr=...) i112 = int_signext(i160, 2) setfield_gc(p167, ConstPtr(ptr85), descr=) @@ -426,7 +422,7 @@ i114 = int_ne(i160, i112) guard_false(i114, descr=...) --TICK-- - i119 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) + i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py --- a/pypy/module/pypyjit/test_pypy_c/test_generators.py +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -21,10 +21,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + ifoo = arraylen_gc(p8, descr=) setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ @@ -50,10 +50,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + i47 = arraylen_gc(p8, descr=) # Should be removed by backend setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ From noreply at buildbot.pypy.org Thu Sep 10 20:38:46 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 10 Sep 2015 20:38:46 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20150910183846.173411C1342@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79588:87a0faff0bd9 Date: 2015-09-10 20:38 +0200 http://bitbucket.org/pypy/pypy/changeset/87a0faff0bd9/ Log: merge diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -43,9 +43,9 @@ i25 = unicodegetitem(p13, i19) p27 = newstr(1) strsetitem(p27, 0, i23) - p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) + p30 = call_r(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) guard_no_exception(descr=...) - i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) + i32 = call_i(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- @@ -80,12 +80,12 @@ i23 = strgetitem(p10, i19) p25 = newstr(1) strsetitem(p25, 0, i23) - p93 = call(ConstClass(fromstr), p25, 16, descr=) + p93 = call_r(ConstClass(fromstr), p25, 16, descr=) guard_no_exception(descr=...) - i95 = getfield_gc_pure(p93, descr=) + i95 = getfield_gc_pure_i(p93, descr=) i96 = int_gt(i95, #) guard_false(i96, descr=...) - i94 = call(ConstClass(rbigint._toint_helper), p93, descr=) + i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=) guard_no_exception(descr=...) i95 = int_add_ovf(i6, i94) guard_no_overflow(descr=...) @@ -108,7 +108,7 @@ i79 = int_gt(i74, 0) guard_true(i79, descr=...) guard_not_invalidated(descr=...) - p80 = call(ConstClass(ll_int2dec__Signed), i74, descr=) + p80 = call_r(ConstClass(ll_int2dec__Signed), i74, descr=) guard_no_exception(descr=...) i85 = strlen(p80) p86 = new(descr=) @@ -119,21 +119,21 @@ setfield_gc(p86, 23, descr=) setfield_gc(p86, 23, descr=) }}} - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - i89 = getfield_gc(p86, descr=) - i90 = getfield_gc(p86, descr=) + i89 = getfield_gc_i(p86, descr=) + i90 = getfield_gc_i(p86, descr=) i91 = int_eq(i89, i90) cond_call(i91, ConstClass(ll_grow_by__stringbuilderPtr_Signed), p86, 1, descr=) guard_no_exception(descr=...) - i92 = getfield_gc(p86, descr=) + i92 = getfield_gc_i(p86, descr=) i93 = int_add(i92, 1) p94 = getfield_gc(p86, descr=) strsetitem(p94, i92, 32) setfield_gc(p86, i93, descr=) - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - p95 = call(..., descr=) # ll_build + p95 = call_r(..., descr=) # ll_build guard_no_exception(descr=...) i96 = strlen(p95) i97 = int_add_ovf(i71, i96) @@ -176,7 +176,7 @@ strsetitem(p35, 3, 104) strsetitem(p35, 4, 95) copystrcontent(p31, p35, 0, 5, i32) - i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) + i49 = call_i(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) guard_value(i49, 1, descr=...) ''') @@ -195,7 +195,7 @@ loops = log.loops_by_filename(self.filepath) loop, = loops assert loop.match_by_id('callone', ''' - p114 = call(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) + p114 = call_r(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) guard_no_exception(descr=...) ''') assert loop.match_by_id('calltwo', '') # nothing diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py --- a/pypy/module/pypyjit/test_pypy_c/test_thread.py +++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py @@ -64,11 +64,11 @@ guard_true(i56, descr=...) p57 = force_token() setfield_gc(p0, p57, descr=) - i58 = call_release_gil(0, _, i37, 1, descr=) + i58 = call_release_gil_i(0, _, i37, 1, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) i58 = int_sub(i44, 1) - i59 = call(ConstClass(RPyThreadReleaseLock), i37, descr=) + i59 = call_i(ConstClass(RPyThreadReleaseLock), i37, descr=) i60 = int_is_true(i59) guard_false(i60, descr=...) guard_not_invalidated(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_weakref.py b/pypy/module/pypyjit/test_pypy_c/test_weakref.py --- a/pypy/module/pypyjit/test_pypy_c/test_weakref.py +++ b/pypy/module/pypyjit/test_pypy_c/test_weakref.py @@ -19,23 +19,23 @@ """, [500]) loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i58 = getfield_gc(p18, descr=) + i58 = getfield_gc_i(p18, descr=) i60 = int_lt(i58, i31) guard_true(i60, descr=...) i61 = int_add(i58, 1) - p62 = getfield_gc(ConstPtr(ptr37), descr=) + p62 = getfield_gc_r(ConstPtr(ptr37), descr=) setfield_gc(p18, i61, descr=) guard_value(p62, ConstPtr(ptr39), descr=...) guard_not_invalidated(descr=...) - p64 = getfield_gc(ConstPtr(ptr40), descr=) + p64 = getfield_gc_r(ConstPtr(ptr40), descr=) guard_value(p64, ConstPtr(ptr42), descr=...) - p65 = getfield_gc(p14, descr=) + p65 = getfield_gc_r(p14, descr=) guard_value(p65, ConstPtr(ptr45), descr=...) - p66 = getfield_gc(p14, descr=) + p66 = getfield_gc_r(p14, descr=) guard_nonnull_class(p66, ..., descr=...) p67 = force_token() setfield_gc(p0, p67, descr=) - p68 = call_may_force(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) + p68 = call_may_force_r(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) guard_nonnull_class(p68, ..., descr=...) From noreply at buildbot.pypy.org Fri Sep 11 12:51:32 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 11 Sep 2015 12:51:32 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: adjusting the resop creation to remove the vectorbox, work in progress Message-ID: <20150911105132.B89A11C11E0@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79589:7783b6299af3 Date: 2015-09-11 12:51 +0200 http://bitbucket.org/pypy/pypy/changeset/7783b6299af3/ Log: adjusting the resop creation to remove the vectorbox, work in progress diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -8,33 +8,44 @@ from rpython.jit.metainterp.jitexc import NotAProfitableLoop -class SchedulerData(object): - pass +class SchedulerState(object): + def __init__(self, graph): + self.renamer = Renamer() + self.graph = graph + self.oplist = [] + self.worklist = [] + + def post_schedule(self): + pass + + def profitable(self): + return self.costmodel.profitable() + + def prepare(self): + pass + + def has_more(self): + return len(self.worklist) > 0 + class Scheduler(object): """ The base class to be instantiated to (re)schedule a vector trace. """ - def __init__(self, graph, sched_data): - assert isinstance(sched_data, SchedulerData) - self.graph = graph - self.schedulable_nodes = self.graph.schedulable_nodes - self.sched_data = sched_data - self.oplist = None - self.renamer = None + def __init__(self): + pass - def has_more(self): - return len(self.schedulable_nodes) > 0 - - def next_index(self, candidate_list): - i = len(candidate_list)-1 - while i >= 0: - candidate = candidate_list[i] - if candidate.emitted: - del candidate_list[i] - i -= 1 + def next(self, state): + worklist = state.worklist + visited = 0 + while len(worklist) > 0: + if visited == len(worklist): + return None + node = worklist.pop() + if node.emitted: continue - if self.schedulable(candidate): - return i - i -= 1 - return -1 + if self.schedulable(node): + return node + worklist.insert(0, node) + visited += 1 + return None def schedulable(self, candidate): """ Is the candidate scheduleable? Boils down to dependency_count == 0 @@ -53,12 +64,14 @@ return False return candidate.depends_count() == 0 - def scheduled(self, node): + def scheduled(self, node, state): """ Call this function if an operation has been emitted adds new operations to the schedule list if their dependency count drops to zero. In addition it keeps the list sorted (see priority) """ + state.renamer.rename(op) + state.unpack_from_vector(op, self) node.position = len(self.oplist) for dep in node.provides()[:]: # COPY to = dep.to @@ -85,36 +98,37 @@ node.clear_dependencies() node.emitted = True - def emit_into(self, oplist, renamer, unpack=False): + def walk_and_emit(self, state): # TODO oplist, renamer, unpack=False): """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ - self.renamer = renamer - self.oplist = oplist - self.unpack = unpack + assert isinstance(state, SchedulerState) + while state.has_more(): + node = self.next(state) + if node: + if not state.emit(node): + if not node.emitted: + op = node.getoperation() + scheduler.scheduled(node, state) + continue - while self.has_more(): - i = self.next_index(self.schedulable_nodes) - if i >= 0: - candidate = self.schedulable_nodes[i] - del self.schedulable_nodes[i] - self.sched_data.schedule_candidate(self, candidate) - continue + # it happens that packs can emit many nodes that have been # added to the scheuldable_nodes list, in this case it could # be that no next exists even though the list contains elements - if not self.has_more(): + if not state.has_more(): break raise AssertionError("schedule failed cannot continue. possible reason: cycle") - jump_node = self.graph.nodes[-1] - jump_op = jump_node.getoperation() - renamer.rename(jump_op) - assert jump_op.getopnum() == rop.JUMP - self.sched_data.unpack_from_vector(jump_op, self) - oplist.append(jump_op) + # TODO + #jump_node = self.graph.nodes[-1] + #jump_op = jump_node.getoperation() + #renamer.rename(jump_op) + #assert jump_op.getopnum() == rop.JUMP + #self.sched_data.unpack_from_vector(jump_op, self) + #oplist.append(jump_op) def vectorbox_outof_box(box, count=-1, size=-1, type='-'): if box.type not in (FLOAT, INT): @@ -178,7 +192,7 @@ @staticmethod def of(box, count=-1): - assert isinstance(box, BoxVector) + assert box.type == 'V' if count == -1: count = box.getcount() return PackType(box.gettype(), box.getsize(), box.getsigned(), count) @@ -210,6 +224,7 @@ assert count > 1 assert self.type in ('i','f') assert self.size > 0 + xxx return BoxVector(self.type, count, self.size, self.signed) def combine(self, other): @@ -312,10 +327,9 @@ self.before_argument_transform(args) self.transform_arguments(args) # - result = op.result - result = self.transform_result(result) + vop = ResOperation(op.vector, args, op.getdescr()) + #result = self.transform_result(op) # - vop = ResOperation(op.vector, args, result, op.getdescr()) if op.is_guard(): assert isinstance(op, GuardResOp) assert isinstance(vop, GuardResOp) @@ -334,7 +348,7 @@ if i >= vbox.getcount(): break op = node.getoperation() - self.sched_data.setvector_of_box(op.result, i, vbox) + self.sched_data.setvector_of_box(op, i, vbox) return vbox def new_result_vector_box(self): @@ -348,9 +362,18 @@ return self.pack.operations def transform_arguments(self, args): - """ Transforming one argument to a vector box argument """ + """ Transforming one argument to a vector box argument + The following cases can occur: + 1) argument is present in the box_to_vbox map. + a) vector can be reused immediatly (simple case) + b) vector is to big + c) vector is to small + 2) argument is not known to reside in a vector + a) expand vars/consts before the label and add as argument + b) expand vars created in the loop body + """ for i,arg in enumerate(args): - if isinstance(arg, BoxVector): + if arg.returns_vector(): continue if not self.is_vector_arg(i): continue @@ -478,7 +501,7 @@ return new_box def _check_vec_pack(self, op): - result = op.result + result = op arg0 = op.getarg(0) arg1 = op.getarg(1) index = op.getarg(2) @@ -754,63 +777,89 @@ raise NotImplementedError("missing vecop for '%s'" % (op.getopname(),)) return op2vecop -class VecScheduleData(SchedulerData): - def __init__(self, vec_reg_size, costmodel, inputargs): +class VecScheduleState(SchedulerState): + def __init__(self, graph, packset, cpu, costmodel): + SchedulerState.__init__(self, graph) self.box_to_vbox = {} - self.vec_reg_size = vec_reg_size + self.cpu = cpu + self.vec_reg_size = cpu.vector_register_size self.invariant_oplist = [] self.invariant_vector_vars = [] self.expanded_map = {} self.costmodel = costmodel self.inputargs = {} - for arg in inputargs: + self.packset = packset + for arg in graph.loop.inputargs: self.inputargs[arg] = None self.seen = {} - def schedule_candidate(self, scheduler, candidate): + def post_schedule(self): + pass + # TODO label rename + if vector: + # XXX + # add accumulation info to the descriptor + #for version in self.loop.versions: + # # this needs to be done for renamed (accum arguments) + # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] + #self.appended_arg_count = len(sched_data.invariant_vector_vars) + ##for guard_node in graph.guards: + ## op = guard_node.getoperation() + ## failargs = op.getfailargs() + ## for i,arg in enumerate(failargs): + ## if arg is None: + ## continue + ## accum = arg.getaccum() + ## if accum: + ## pass + ## #accum.save_to_descr(op.getdescr(),i) + #self.has_two_labels = len(sched_data.invariant_oplist) > 0 + #self.loop.operations = self.prepend_invariant_operations(sched_data) + pass + + + def profitable(self): + return self.costmodel.profitable() + + def prepare(self): + SchedulerState.prepare(self) + self.graph.prepare_for_scheduling() + self.packset.accumulate_prepare(self) + for arg in self.graph.loop.label.getarglist(): + self.seen[arg] = None + + def emit(self, node, scheduler): """ If you implement a scheduler this operations is called to emit the actual operation into the oplist of the scheduler. """ - renamer = scheduler.renamer - if candidate.pack: - for node in candidate.pack.operations: - renamer.rename(node.getoperation()) + if node.pack: + for node in node.pack.operations: scheduler.scheduled(node) - self.as_vector_operation(scheduler, candidate.pack) - else: - op = candidate.getoperation() - renamer.rename(op) - self.unpack_from_vector(op, scheduler) - scheduler.scheduled(candidate) - op = candidate.getoperation() - # - # prevent some instructions in the resulting trace! - if op.getopnum() in (rop.DEBUG_MERGE_POINT, - rop.GUARD_EARLY_EXIT): - return - scheduler.oplist.append(op) + self.as_vector_operation(node.pack) + return True + return False - def as_vector_operation(self, scheduler, pack): + + def as_vector_operation(self, pack): """ Transform a pack into a single or several operation. Calls the as_vector_operation of the OpToVectorOp implementation. """ assert pack.opcount() > 1 # properties that hold for the pack are: - # + isomorphism (see func above) + # + isomorphism (see func) # + tightly packed (no room between vector elems) - oplist = scheduler.oplist - position = len(oplist) - op = pack.operations[0].getoperation() - determine_trans(op).as_vector_operation(pack, self, scheduler, oplist) + position = len(self.oplist) + op = pack.leftmost().getoperation() + determine_trans(op).as_vector_operation(pack, self, self.oplist) # if pack.is_accumulating(): box = oplist[position].result assert box is not None for node in pack.operations: op = node.getoperation() - assert op.result is not None - scheduler.renamer.start_renaming(op.result, box) + assert not op.returns_void() + scheduler.renamer.start_renaming(op, box) def unpack_from_vector(self, op, scheduler): """ If a box is needed that is currently stored within a vector @@ -820,17 +869,17 @@ # unpack for an immediate use for i, arg in enumerate(op.getarglist()): - if isinstance(arg, Box): + if not arg.is_constant(): argument = self._unpack_from_vector(i, arg, scheduler) if arg is not argument: op.setarg(i, argument) - if op.result: - self.seen[op.result] = None + if not op.returns_void(): + self.seen[op] = None # unpack for a guard exit if op.is_guard(): fail_args = op.getfailargs() for i, arg in enumerate(fail_args): - if arg and isinstance(arg, Box): + if arg and not arg.is_constant(): argument = self._unpack_from_vector(i, arg, scheduler) if arg is not argument: fail_args[i] = argument @@ -865,7 +914,7 @@ def setvector_of_box(self, box, off, vector): assert off < vector.getcount() - assert not isinstance(box, BoxVector) + assert box.type != 'V' self.box_to_vbox[box] = (off, vector) def opcount_filling_vector_register(pack, vec_reg_size): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -6,13 +6,28 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, Dependency, IndexVar, MemoryRef, Node) -from rpython.jit.metainterp.optimizeopt.vector import TraceLoop +from rpython.jit.metainterp.optimizeopt.vector import VectorLoop from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.backend.llgraph.runner import ArrayDescr from rpython.rtyper.lltypesystem import rffi from rpython.rtyper.lltypesystem import lltype from rpython.conftest import option +class FakeDependencyGraph(DependencyGraph): + """ A dependency graph that is able to emit every instruction + one by one. """ + def __init__(self, loop): + self.loop = loop + if isinstance(loop, list): + self.nodes = loop + else: + operations = loop.operations + self.nodes = [Node(op,i) for i,op in \ + enumerate(operations)] + self.schedulable_nodes = list(reversed(self.nodes)) + self.guards = [] + + class DependencyBaseTest(BaseTest): def setup_method(self, method): @@ -26,12 +41,20 @@ assert node.independent(node) return self.last_graph - def parse_loop(self, ops): + def parse_loop(self, ops, add_label=True, **kwargs): loop = self.parse(ops, postprocess=self.postprocess) + loop.operations = filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) token = JitCellToken() - label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) - loop = TraceLoop(label, loop.operations[:-1], loop.operations[-1]) + if add_label: + label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) + else: + label = loop.operations[0] + label.setdescr(TargetToken(token)) + loop = VectorLoop(label, loop.operations[1:-1], loop.operations[-1]) loop.jump.setdescr(token) + for op in loop.operations: + if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: + op.setdescr(compile.ResumeAtLoopHeaderDescr()) return loop def assert_edges(self, graph, edge_list, exceptions): @@ -533,8 +556,7 @@ n1,n2 = FakeNode(1), FakeNode(2) n1.edge_to(n2); n2.edge_to(n1) - graph = FakeDependencyGraph() - graph.nodes = [n1,n2] + graph = FakeDependencyGraph([n1,n2]) cycle = graph.cycles() assert cycle == [n1, n2] @@ -547,7 +569,7 @@ n1,n2,n3,n4 = FakeNode(1), FakeNode(2), FakeNode(3), FakeNode(4) n1.edge_to(n3); n3.edge_to(n4); n4.edge_to(n1) - graph = FakeDependencyGraph() + graph = FakeDependencyGraph([n1,n2]) graph.nodes = [n1,n2,n3] cycle = graph.cycles() assert cycle is not None @@ -584,10 +606,6 @@ def __repr__(self): return "n%d" % self.opidx -class FakeDependencyGraph(DependencyGraph): - def __init__(self): - pass - class TestLLtype(BaseTestDependencyGraph, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -3,13 +3,14 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.util import equaloplists from rpython.jit.metainterp.optimizeopt.renamer import Renamer -from rpython.jit.metainterp.optimizeopt.vec import (VecScheduleData, +from rpython.jit.metainterp.optimizeopt.vector import (VecScheduleState, Pack, Pair, NotAProfitableLoop, VectorizingOptimizer, X86_CostModel, PackSet) from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph -from rpython.jit.metainterp.optimizeopt.schedule import PackType +from rpython.jit.metainterp.optimizeopt.schedule import PackType, Scheduler from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin -from rpython.jit.metainterp.optimizeopt.test.test_dependency import DependencyBaseTest +from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest, + FakeDependencyGraph) from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, FakeJitDriverStaticData) from rpython.jit.metainterp.resoperation import rop, ResOperation @@ -29,19 +30,10 @@ self.packs = packs self.vec_reg_size = 16 -class FakeDependencyGraph(DependencyGraph): - """ A dependency graph that is able to emit every instruction - one by one. """ - def __init__(self, loop): - self.nodes = [Node(op,i) for i,op in \ - enumerate(loop.operations)] - self.schedulable_nodes = list(reversed(self.nodes)) - self.guards = [] - class SchedulerBaseTest(DependencyBaseTest): - def namespace(self): - return { + def setup_class(self): + self.namespace = { 'double': self.floatarraydescr, 'float': self.float32arraydescr, 'long': self.arraydescr, @@ -50,12 +42,8 @@ 'char': self.chararraydescr, } - def parse(self, source, inc_label_jump=True, - pargs=2, - iargs=10, - fargs=6, - additional_args=None, - replace_args=None): + def parse_trace(self, source, inc_label_jump=True, pargs=2, iargs=10, + fargs=6, additional_args=None, replace_args=None): args = [] for prefix, rang in [('p',range(pargs)), ('i',range(iargs)), @@ -75,16 +63,8 @@ joinedargs = ','.join(args) fmt = (indent, joinedargs, source, indent, joinedargs) src = "%s[%s]\n%s\n%sjump(%s)" % fmt - loop = opparse(src, cpu=self.cpu, namespace=self.namespace()) - if inc_label_jump: - token = JitCellToken() - label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) - loop.operations = [label] + loop.operations - loop.graph = FakeDependencyGraph(loop) - return loop - else: - loop.graph = FakeDependencyGraph(loop) - del loop.operations[-1] + loop = self.parse_loop(src) + loop.graph = FakeDependencyGraph(loop) return loop def pack(self, loop, l, r, input_type, output_type): @@ -92,21 +72,8 @@ def schedule(self, loop, packs, vec_reg_size=16, prepend_invariant=False, overwrite_funcs=None): - ops = [] - cm = X86_CostModel(0, vec_reg_size) - def profitable(): - return True - cm.profitable = profitable - vsd = VecScheduleData(vec_reg_size, cm, loop.inputargs[:]) - for name, overwrite in (overwrite_funcs or {}).items(): - setattr(vsd, name, overwrite) - renamer = Renamer() - metainterp_sd = FakeMetaInterpStaticData(self.cpu) - jitdriver_sd = FakeJitDriverStaticData() - opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, loop, 0) - opt.costmodel = cm - opt.dependency_graph = loop.graph - del loop.graph + cm = X86_CostModel(self.cpu, 0) + cm.profitable = lambda: True pairs = [] for pack in packs: for i in range(len(pack.operations)-1): @@ -115,29 +82,39 @@ o2 = pack.operations[i+1] pair = Pair(o1,o2,pack.input_type,pack.output_type) pairs.append(pair) - - opt.packset = FakePackSet(pairs) - + packset = FakePackSet(pairs) + state = VecScheduleState(loop.graph, packset, self.cpu, cm) + for name, overwrite in (overwrite_funcs or {}).items(): + setattr(state, name, overwrite) + renamer = Renamer() + metainterp_sd = FakeMetaInterpStaticData(self.cpu) + jitdriver_sd = FakeJitDriverStaticData() + opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, 0) + opt.packset = packset if not prepend_invariant: - def pio(oplist, labels): - return oplist - vsd.prepend_invariant_operations = pio - + state.prepend_invariant_operations = lambda list, _: list opt.combine_packset() - opt.schedule(True, sched_data=vsd) - - loop.operations = \ - [op for op in loop.operations \ - if not (op.is_final() or op.is_label())] - - return loop - - def assert_operations_match(self, loop_a, loop_b): - assert equaloplists(loop_a.operations, loop_b.operations) + opt.schedule(state) class Test(SchedulerBaseTest, LLtypeMixin): + + def test_next_must_not_loop_forever(self): + scheduler = Scheduler() + def schedulable(node): + node.count += 1 + return False + scheduler.schedulable = schedulable + class State(object): pass + class Node(object): emitted = False; pack = None; count = 0 + state = State() + state.worklist = [Node(), Node(), Node(), Node(), Node()] + assert scheduler.next(state) is None + for node in state.worklist: + assert node.count == 1 + # must return here, then the test passed + def test_schedule_split_load(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" f10 = raw_load_f(p0, i0, descr=float) f11 = raw_load_f(p0, i1, descr=float) f12 = raw_load_f(p0, i2, descr=float) @@ -147,15 +124,15 @@ """) pack1 = self.pack(loop1, 0, 6, None, F32) loop2 = self.schedule(loop1, [pack1]) - loop3 = self.parse(""" - v10[i32|4] = vec_raw_load(p0, i0, 4, descr=float) + loop3 = self.parse_trace(""" + v10[i32|4] = vec_raw_load_i(p0, i0, 4, descr=float) f10 = raw_load_f(p0, i4, descr=float) f11 = raw_load_f(p0, i5, descr=float) """, False) self.assert_equal(loop2, loop3) def test_int_to_float(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = raw_load(p0, i0, descr=long) i11 = raw_load(p0, i1, descr=long) i12 = int_signext(i10, 4) @@ -167,21 +144,21 @@ pack2 = self.pack(loop1, 2, 4, I64, I32_2) pack3 = self.pack(loop1, 4, 6, I32_2, F32_2) loop2 = self.schedule(loop1, [pack1, pack2, pack3]) - loop3 = self.parse(""" - v10[i64|2] = vec_raw_load(p0, i0, 2, descr=long) + loop3 = self.parse_trace(""" + v10[i64|2] = vec_raw_load_i(p0, i0, 2, descr=long) v20[i32|2] = vec_int_signext(v10[i64|2], 4) v30[f64|2] = vec_cast_int_to_float(v20[i32|2]) """, False) self.assert_equal(loop2, loop3) def test_scalar_pack(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_add(i0, 73) i11 = int_add(i1, 73) """) pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v10[i64|2] = vec_box(2) v20[i64|2] = vec_int_pack(v10[i64|2], i0, 0, 1) v30[i64|2] = vec_int_pack(v20[i64|2], i1, 1, 1) @@ -191,13 +168,13 @@ """, False) self.assert_equal(loop2, loop3) - loop1 = self.parse(""" + loop1 = self.parse_trace(""" f10 = float_add(f0, 73.0) f11 = float_add(f1, 73.0) """) pack1 = self.pack(loop1, 0, 2, F64, F64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v10[f64|2] = vec_box(2) v20[f64|2] = vec_float_pack(v10[f64|2], f0, 0, 1) v30[f64|2] = vec_float_pack(v20[f64|2], f1, 1, 1) @@ -208,7 +185,7 @@ self.assert_equal(loop2, loop3) def test_scalar_remember_expansion(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" f10 = float_add(f0, f5) f11 = float_add(f1, f5) f12 = float_add(f10, f5) @@ -217,7 +194,7 @@ pack1 = self.pack(loop1, 0, 2, F64, F64) pack2 = self.pack(loop1, 2, 4, F64, F64) loop2 = self.schedule(loop1, [pack1, pack2], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v10[f64|2] = vec_box(2) v20[f64|2] = vec_float_pack(v10[f64|2], f0, 0, 1) v30[f64|2] = vec_float_pack(v20[f64|2], f1, 1, 1) @@ -235,7 +212,7 @@ raise Exception("could not find %s in args %s" % (name, loop.inputargs)) def test_signext_int32(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_signext(i1, 4) i11 = int_signext(i1, 4) """, additional_args=['v10[i64|2]']) @@ -247,13 +224,13 @@ overwrite_funcs = { 'getvector_of_box': i1inv103204, }) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v11[i32|2] = vec_int_signext(v10[i64|2], 4) """, False, additional_args=['v10[i64|2]']) self.assert_equal(loop2, loop3) def test_cast_float_to_int(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" f10 = raw_load(p0, i1, descr=double) f11 = raw_load(p0, i2, descr=double) f12 = raw_load(p0, i3, descr=double) @@ -301,11 +278,11 @@ overwrite_funcs={ '_prevent_signext': void }) - loop3 = self.parse(""" - v10[f64|2] = vec_raw_load(p0, i1, 2, descr=double) - v11[f64|2] = vec_raw_load(p0, i3, 2, descr=double) - v12[f64|2] = vec_raw_load(p0, i5, 2, descr=double) - v13[f64|2] = vec_raw_load(p0, i7, 2, descr=double) + loop3 = self.parse_trace(""" + v10[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) + v11[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) + v12[f64|2] = vec_raw_load_f(p0, i5, 2, descr=double) + v13[f64|2] = vec_raw_load_f(p0, i7, 2, descr=double) v14[i32|2] = vec_cast_float_to_int(v10[f64|2]) v15[i32|2] = vec_cast_float_to_int(v11[f64|2]) v16[i32|2] = vec_cast_float_to_int(v12[f64|2]) @@ -322,7 +299,7 @@ self.assert_equal(loop2, loop3) def test_cast_float_to_single_float(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" f10 = raw_load(p0, i1, descr=double) f11 = raw_load(p0, i2, descr=double) f12 = raw_load(p0, i3, descr=double) @@ -342,9 +319,9 @@ pack2 = self.pack(loop1, 4, 8, F64, I32_2) pack3 = self.pack(loop1, 8, 12, I32, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3]) - loop3 = self.parse(""" - v44[f64|2] = vec_raw_load(p0, i1, 2, descr=double) - v45[f64|2] = vec_raw_load(p0, i3, 2, descr=double) + loop3 = self.parse_trace(""" + v44[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) + v45[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) v46[i32|2] = vec_cast_float_to_singlefloat(v44[f64|2]) v47[i32|2] = vec_cast_float_to_singlefloat(v45[f64|2]) v41[i32|4] = vec_int_pack(v46[i32|2], v47[i32|2], 2, 2) @@ -353,7 +330,7 @@ self.assert_equal(loop2, loop3) def test_all(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = raw_load(p0, i1, descr=long) i11 = raw_load(p0, i2, descr=long) # @@ -367,9 +344,9 @@ pack2 = self.pack(loop1, 2, 4, I64, I64) pack3 = self.pack(loop1, 4, 6, I64, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v9[i64|2] = vec_int_expand(255,2) - v10[i64|2] = vec_raw_load(p0, i1, 2, descr=long) + v10[i64|2] = vec_raw_load_i(p0, i1, 2, descr=long) v11[i64|2] = vec_int_and(v10[i64|2], v9[i64|2]) guard_true(v11[i64|2]) [] """, False) @@ -377,7 +354,7 @@ def test_split_load_store(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = raw_load(p0, i1, descr=float) i11 = raw_load(p0, i2, descr=float) i12 = raw_load(p0, i3, descr=float) @@ -388,8 +365,8 @@ pack1 = self.pack(loop1, 0, 4, None, I32) pack2 = self.pack(loop1, 4, 6, I32_2, None) loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True) - loop3 = self.parse(""" - v1[i32|4] = vec_raw_load(p0, i1, 4, descr=float) + loop3 = self.parse_trace(""" + v1[i32|4] = vec_raw_load_i(p0, i1, 4, descr=float) i10 = vec_int_unpack(v1[i32|4], 0, 1) raw_store(p0, i3, i10, descr=float) i11 = vec_int_unpack(v1[i32|4], 1, 1) @@ -400,13 +377,13 @@ self.assert_equal(loop2, loop3) def test_split_arith(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_and(255, i1) i11 = int_and(255, i1) """) pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v1[i64|2] = vec_int_expand(255,2) v2[i64|2] = vec_int_expand(i1,2) v3[i64|2] = vec_int_and(v1[i64|2], v2[i64|2]) @@ -414,13 +391,13 @@ self.assert_equal(loop2, loop3) def test_split_arith(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_and(255, i1) i11 = int_and(255, i1) """) pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v1[i64|2] = vec_int_expand(255, 2) v2[i64|2] = vec_int_expand(i1, 2) v3[i64|2] = vec_int_and(v1[i64|2], v2[i64|2]) @@ -428,7 +405,7 @@ self.assert_equal(loop2, loop3) def test_no_vec_impl(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_and(255, i1) i11 = int_and(255, i2) i12 = uint_floordiv(i10,1) @@ -439,7 +416,7 @@ pack1 = self.pack(loop1, 0, 2, I64, I64) pack4 = self.pack(loop1, 4, 6, I64, I64) loop2 = self.schedule(loop1, [pack1,pack4], prepend_invariant=True) - loop3 = self.parse(""" + loop3 = self.parse_trace(""" v1[i64|2] = vec_int_expand(255,2) v2[i64|2] = vec_box(2) v3[i64|2] = vec_int_pack(v2[i64|2], i1, 0, 1) @@ -457,7 +434,7 @@ self.assert_equal(loop2, loop3) def test_split_cast(self): - trace = self.parse(""" + trace = self.parse_trace(""" f10 = cast_int_to_float(i1) f11 = cast_int_to_float(i2) f12 = cast_int_to_float(i3) @@ -470,7 +447,7 @@ assert len(packs) == 2 def test_combine_packset_nearly_empty_pack(self): - trace = self.parse(""" + trace = self.parse_trace(""" i10 = int_add(i1, i3) i11 = int_add(i2, i3) """) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -11,9 +11,9 @@ import rpython.jit.metainterp.optimizeopt.optimizer as optimizeopt import rpython.jit.metainterp.optimizeopt.virtualize as virtualize from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph -from rpython.jit.metainterp.optimizeopt.vectorize import (VectorizingOptimizer, MemoryRef, +from rpython.jit.metainterp.optimizeopt.vector import (VectorizingOptimizer, MemoryRef, isomorphic, Pair, NotAVectorizeableLoop, NotAProfitableLoop, GuardStrengthenOpt, - CostModel) + CostModel, VectorLoop) from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp import compile from rpython.jit.metainterp.resoperation import rop, ResOperation @@ -41,25 +41,6 @@ jitdriver_sd = FakeJitDriverStaticData() - def parse_loop(self, ops, add_label=True): - loop = self.parse(ops, postprocess=self.postprocess) - token = JitCellToken() - pre = [] - tt = TargetToken(token) - if add_label: - pre = [ResOperation(rop.LABEL, loop.inputargs, None, descr=tt)] - else: - for i,op in enumerate(loop.operations): - if op.getopnum() == rop.LABEL: - op.setdescr(tt) - loop.operations = pre + filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) - if loop.operations[-1].getopnum() == rop.JUMP: - loop.operations[-1].setdescr(token) - for op in loop.operations: - if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: - op.setdescr(compile.ResumeAtLoopHeaderDescr()) - return loop - def assert_vectorize(self, loop, expected_loop, call_pure_results=None): self._do_optimize_loop(loop, call_pure_results, export_state=True) self.assert_equal(loop, expected_loop) @@ -67,7 +48,7 @@ def vectoroptimizer(self, loop): metainterp_sd = FakeMetaInterpStaticData(self.cpu) jitdriver_sd = FakeJitDriverStaticData() - opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, loop, 0) + opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, 0) label_index = loop.find_first_index(rop.LABEL) opt.orig_label_args = loop.operations[label_index].getarglist()[:] return opt @@ -89,48 +70,48 @@ guard.setdescr(compile.ResumeAtLoopHeaderDescr()) loop.operations.insert(idx+1, guard) self.show_dot_graph(DependencyGraph(opt.loop), "original_" + self.test_name) - opt.analyse_index_calculations() - if opt.dependency_graph is not None: + graph = opt.analyse_index_calculations() + if graph is not None: cycle = opt.dependency_graph.cycles() if cycle is not None: print "CYCLE found %s" % cycle self.show_dot_graph(opt.dependency_graph, "early_exit_" + self.test_name) assert cycle is None - opt.schedule(False) + loop.operations = opt.schedule(False) opt.unroll_loop_iterations(loop, unroll_factor) opt.loop.operations = opt.get_newoperations() self.debug_print_operations(opt.loop) opt.clear_newoperations() - opt.dependency_graph = DependencyGraph(loop) - self.last_graph = opt.dependency_graph + graph = DependencyGraph(loop) + self.last_graph = graph self.show_dot_graph(self.last_graph, self.test_name) - return opt + return opt, graph def init_packset(self, loop, unroll_factor = -1): - opt = self.vectoroptimizer_unrolled(loop, unroll_factor) - opt.find_adjacent_memory_refs() + opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs(graph) return opt def extend_packset(self, loop, unroll_factor = -1): - opt = self.vectoroptimizer_unrolled(loop, unroll_factor) - opt.find_adjacent_memory_refs() + opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs(graph) opt.extend_packset() return opt def combine_packset(self, loop, unroll_factor = -1): - opt = self.vectoroptimizer_unrolled(loop, unroll_factor) - opt.find_adjacent_memory_refs() + opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() return opt def schedule(self, loop, unroll_factor = -1, with_guard_opt=False): - opt = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.costmodel = FakeCostModel() - opt.find_adjacent_memory_refs() + opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() - opt.schedule(True) + opt.schedule(graph, True) if with_guard_opt: gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) gso.propagate_all_forward(opt.loop) @@ -204,8 +185,7 @@ class BaseTestVectorize(VecTestHelper): - def test_vectorize_skip_impossible_1(self): - """ this trace does not contain a raw load / raw store from an array """ + def test_vectorize_skip(self): ops = """ [p0,i0] i1 = int_add(i0,1) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -20,7 +20,7 @@ from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo -from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleData, +from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, getunpackopnum, PackType, determine_input_output_types) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt @@ -31,9 +31,10 @@ from rpython.rlib.jit import Counters from rpython.rtyper.lltypesystem import lltype, rffi -class TraceLoop(object): +class VectorLoop(object): def __init__(self, label, oplist, jump): self.label = label + self.inputargs = label.getarglist() self.prefix = [] self.prefix_label = None assert self.label.getopnum() == rop.LABEL @@ -41,7 +42,7 @@ self.jump = jump assert self.jump.getopnum() == rop.JUMP - def all_operations(self): + def operation_list(self): return [self.label] + self.operations + [self.jump] def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): @@ -52,10 +53,10 @@ # the original loop (output of optimize_unroll) info = LoopVersionInfo(loop_info) version = info.snapshot(loop_ops, info.label_op) - loop = TraceLoop(loop_info.label_op, loop_ops[:-1], loop_ops[-1]) + loop = VectorLoop(loop_info.label_op, loop_ops[:-1], loop_ops[-1]) try: debug_start("vec-opt-loop") - metainterp_sd.logger_noopt.log_loop([], loop.all_operations(), -2, None, None, "pre vectorize") + metainterp_sd.logger_noopt.log_loop([], loop.operation_list(), -2, None, None, "pre vectorize") metainterp_sd.profiler.count(Counters.OPT_VECTORIZE_TRY) # start = time.clock() @@ -67,7 +68,7 @@ end = time.clock() # metainterp_sd.profiler.count(Counters.OPT_VECTORIZED) - metainterp_sd.logger_noopt.log_loop([], loop.all_operations(), -2, None, None, "post vectorize") + metainterp_sd.logger_noopt.log_loop([], loop.operation_list(), -2, None, None, "post vectorize") # nano = int((end-start)*10.0**9) debug_print("# vecopt factor: %d opcount: (%d -> %d) took %dns" % \ @@ -142,8 +143,7 @@ def __init__(self, metainterp_sd, jitdriver_sd, cost_threshold): Optimizer.__init__(self, metainterp_sd, jitdriver_sd) self.cpu = metainterp_sd.cpu - self.costmodel = X86_CostModel(cost_threshold, self.cpu.vector_register_size) - self.dependency_graph = None + self.cost_threshold = cost_threshold self.packset = None self.unroll_count = 0 self.smallest_type_bytes = 0 @@ -171,9 +171,10 @@ raise NotAVectorizeableLoop() # find index guards and move to the earliest position - self.analyse_index_calculations(loop) - if self.dependency_graph is not None: - self.schedule(False) # reorder the trace + graph = self.analyse_index_calculations(loop) + if graph is not None: + state = SchedulerState(graph) + self.schedule(state) # reorder the trace # unroll self.unroll_count = self.get_unroll_count(vsize) @@ -182,13 +183,15 @@ self.clear_newoperations(); # vectorize - self.dependency_graph = DependencyGraph(self.loop) + graph = DependencyGraph(loop) self.find_adjacent_memory_refs() self.extend_packset() self.combine_packset() - self.costmodel.reset_savings() - self.schedule(True) - if not self.costmodel.profitable(): + # TODO move cost model to CPU + costmodel = X86_CostModel(self.cpu, self.cost_threshold) + state = VecScheduleState(graph, self.packset, self.cpu, costmodel) + self.schedule(state) + if not state.profitable(): raise NotAProfitableLoop() def emit_unrolled_operation(self, op): @@ -308,7 +311,7 @@ unroll_count = simd_vec_reg_bytes // byte_count return unroll_count-1 # it is already unrolled once - def find_adjacent_memory_refs(self): + def find_adjacent_memory_refs(self, graph): """ The pre pass already builds a hash of memory references and the operations. Since it is in SSA form there are no array indices. If there are two array accesses in the unrolled loop @@ -320,7 +323,6 @@ operations = loop.operations self.packset = PackSet(self.cpu.vector_register_size) - graph = self.dependency_graph memory_refs = graph.memory_refs.items() # initialize the pack set for node_a,memref_a in memory_refs: @@ -447,59 +449,22 @@ if fail: assert False - def schedule(self, vector=False, sched_data=None): + def schedule(self, state): # TODO vector=False, sched_data=None): """ Scheduling the trace and emitting vector operations for packed instructions. """ - - self.clear_newoperations() - if sched_data is None: - sched_data = VecScheduleData(self.cpu.vector_register_size, - self.costmodel, self.orig_label_args) - self.dependency_graph.prepare_for_scheduling() - scheduler = Scheduler(self.dependency_graph, sched_data) - renamer = Renamer() - # - if vector: - self.packset.accumulate_prepare(sched_data, renamer) - # - for node in scheduler.schedulable_nodes: - op = node.getoperation() - if op.is_label(): - seen = sched_data.seen - for arg in op.getarglist(): - sched_data.seen[arg] = None - break - # - scheduler.emit_into(self._newoperations, renamer, unpack=vector) + state.prepare() + scheduler = Scheduler() + scheduler.walk_and_emit(state) # if not we_are_translated(): - for node in self.dependency_graph.nodes: + for node in graph.nodes: assert node.emitted - if vector and not self.costmodel.profitable(): + # + if state.profitable(): return - if vector: - # add accumulation info to the descriptor - for version in self.loop.versions: - # this needs to be done for renamed (accum arguments) - version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] - self.appended_arg_count = len(sched_data.invariant_vector_vars) - #for guard_node in self.dependency_graph.guards: - # op = guard_node.getoperation() - # failargs = op.getfailargs() - # for i,arg in enumerate(failargs): - # if arg is None: - # continue - # accum = arg.getaccum() - # if accum: - # pass - # #accum.save_to_descr(op.getdescr(),i) - self.has_two_labels = len(sched_data.invariant_oplist) > 0 - self.loop.operations = self.prepend_invariant_operations(sched_data) - else: - self.loop.operations = self._newoperations - - self.clear_newoperations() + # + state.post_schedule() def prepend_invariant_operations(self, sched_data): """ Add invariant operations to the trace loop. returns the operation list @@ -540,7 +505,7 @@ that guards fail 'early' and relax dependencies. Without this step vectorization would not be possible! """ - self.dependency_graph = graph = DependencyGraph(loop) + graph = DependencyGraph(loop) ee_guard_node = graph.getnode(0) if ee_guard_node.getopnum() != rop.GUARD_EARLY_EXIT: raise NotAVectorizeableLoop() @@ -618,9 +583,9 @@ The main reaons to have this is of frequent unpack instructions, and the missing ability (by design) to detect not vectorizable loops. """ - def __init__(self, threshold, vec_reg_size): + def __init__(self, cpu, threshold): self.threshold = threshold - self.vec_reg_size = vec_reg_size + self.vec_reg_size = cpu.vector_register_size self.savings = 0 def reset_savings(self): @@ -850,11 +815,12 @@ # return None, -1 - def accumulate_prepare(self, sched_data, renamer): - vec_reg_size = sched_data.vec_reg_size + def accumulate_prepare(self, state): + vec_reg_size = state.vec_reg_size for pack in self.packs: if not pack.is_accumulating(): continue + xxx accum = pack.accum # create a new vector box for the parameters box = pack.input_type.new_vector_box() @@ -862,27 +828,27 @@ # reset the box to zeros or ones if accum.operator == Accum.PLUS: op = ResOperation(rop.VEC_BOX, [ConstInt(size)], box) - sched_data.invariant_oplist.append(op) + state.invariant_oplist.append(op) result = box.clonebox() op = ResOperation(rop.VEC_INT_XOR, [box, box], result) - sched_data.invariant_oplist.append(op) + state.invariant_oplist.append(op) box = result elif accum.operator == Accum.MULTIPLY: # multiply is only supported by floats op = ResOperation(rop.VEC_FLOAT_EXPAND, [ConstFloat(1.0), ConstInt(size)], box) - sched_data.invariant_oplist.append(op) + state.invariant_oplist.append(op) else: - raise NotImplementedError("can only handle + and *") + raise NotImplementedError("can only handle %s" % accum.operator) result = box.clonebox() assert isinstance(result, BoxVector) result.accum = accum # pack the scalar value op = ResOperation(getpackopnum(box.gettype()), [box, accum.var, ConstInt(0), ConstInt(1)], result) - sched_data.invariant_oplist.append(op) + state.invariant_oplist.append(op) # rename the variable with the box - sched_data.setvector_of_box(accum.getoriginalbox(), 0, result) # prevent it from expansion - renamer.start_renaming(accum.getoriginalbox(), result) + state.setvector_of_box(accum.getoriginalbox(), 0, result) # prevent it from expansion + state.renamer.start_renaming(accum.getoriginalbox(), result) def split_overloaded_packs(self): newpacks = [] diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -66,6 +66,9 @@ def is_inputarg(self): return False + def returns_vector(self): + return False + def ResOperation(opnum, args, descr=None): cls = opclasses[opnum] op = cls() @@ -88,6 +91,7 @@ return self._forwarded + class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" @@ -101,8 +105,7 @@ type = 'v' boolreflex = -1 boolinverse = -1 - vector = -1 - casts = ('\x00', -1, '\x00', -1) + vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement def getopnum(self): return self.opnum @@ -357,6 +360,12 @@ def is_label(self): return self.getopnum() == rop.LABEL + def returns_void(self): + return self.type == 'v' + + def returns_vector(self): + return self.type != 'v' and self.vector == -2 + # =================== # Top of the hierachy # =================== @@ -365,6 +374,9 @@ pass class CastResOp(AbstractResOp): + _attrs_ = ('casts') + casts = ('\x00', -1, '\x00', -1) + def casts_box(self): return True @@ -546,8 +558,6 @@ _attrs_ = ('item_type','item_count','item_size','item_signed','accum') _extended_display = False - type = 'V' - #def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): # assert item_type in (FLOAT, INT) # self.item_type = item_type @@ -651,6 +661,13 @@ def reset_value(self): self.setref_base(lltype.nullptr(llmemory.GCREF.TO)) +class InputArgVector(VectorOp, AbstractInputArg): + def __init__(self): + pass + + def returns_vector(self): + return True + # ============ # arity mixins # ============ @@ -1154,6 +1171,8 @@ mixins.append(RefOp) else: assert result_type == 'n' + if name.startswith('VEC'): + mixins.insert(1,VectorOp) cls_name = '%s_OP' % name bases = (get_base_class(tuple(mixins), baseclass),) @@ -1271,6 +1290,8 @@ cls.vector = _opvector[opnum] if name in _cast_ops: cls.casts = _cast_ops[name] + if name.startswith('VEC'): + cls.vector = -2 setup2() del _opboolinverse del _opboolreflex From noreply at buildbot.pypy.org Fri Sep 11 15:22:37 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 11 Sep 2015 15:22:37 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: PPC Backend #3 (1/2): intermediate progress Message-ID: <20150911132237.3C3E41C11E0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79590:b1f98b2e68b5 Date: 2015-09-02 18:44 +0200 http://bitbucket.org/pypy/pypy/changeset/b1f98b2e68b5/ Log: PPC Backend #3 (1/2): intermediate progress diff --git a/rpython/jit/backend/ppc/arch.py b/rpython/jit/backend/ppc/arch.py --- a/rpython/jit/backend/ppc/arch.py +++ b/rpython/jit/backend/ppc/arch.py @@ -1,5 +1,6 @@ # Constants that depend on whether we are on 32-bit or 64-bit +import sys from rpython.jit.backend.ppc import register as r import sys @@ -20,6 +21,10 @@ IS_PPC_64 = not IS_PPC_32 MY_COPY_OF_REGS = 0 +IS_BIG_ENDIAN = sys.byteorder == 'big' +IS_LITTLE_ENDIAN = sys.byteorder == 'little' +assert IS_BIG_ENDIAN ^ IS_LITTLE_ENDIAN + #FORCE_INDEX = WORD #GPR_SAVE_AREA = len(NONVOLATILES) * WORD #FLOAT_INT_CONVERSION = WORD @@ -32,28 +37,29 @@ #FORCE_INDEX_OFS = (len(MANAGED_REGS) + len(MANAGED_FP_REGS)) * WORD +# BIG ENDIAN LITTLE ENDIAN # -# +--------------------+ <- SP + STD_FRAME_SIZE +# +--------------------+ <- SP + STD_FRAME_SIZE # | general registers | # | save area | -# +--------------------+ <- SP + 120 -# | Local vars (*) | -# +--------------------+ <- SP + 112 +# +--------------------+ <- SP + 120 SP + 104 +# | Local vars | +# +--------------------+ <- SP + 112 SP + 96 # | Parameter save | # | area (8 args max) | -# +--------------------+ <- SP + 48 +# +--------------------+ <- SP + 48 SP + 32 # | TOC (unused) | -# +--------------------+ <- SP + 40 +# +--------------------+ <- SP + 40 SP + 24 # | link ed. (unused) | -# +--------------------+ <- SP + 32 +# +--------------------+ <- SP + 32 absent # | compiler (unused) | -# +--------------------+ <- SP + 24 +# +--------------------+ <- SP + 24 absent # | LR save area | -# +--------------------+ <- SP + 16 +# +--------------------+ <- SP + 16 SP + 16 # | CR save (unused) | -# +--------------------+ <- SP + 8 +# +--------------------+ <- SP + 8 SP + 8 # | SP back chain | -# +--------------------+ <- SP +# +--------------------+ <- SP SP # The local variables area contains only a copy of the 2nd argument # passed to the machine code function, which is the ll_threadlocal_addr. @@ -62,9 +68,10 @@ LR_BC_OFFSET = 16 -PARAM_SAVE_AREA_OFFSET = 48 -THREADLOCAL_ADDR_OFFSET = 112 -GPR_SAVE_AREA_OFFSET = 120 +_GAP = 0 if IS_BIG_ENDIAN else 16 +PARAM_SAVE_AREA_OFFSET = 48 - _GAP +THREADLOCAL_ADDR_OFFSET = 112 - _GAP +GPR_SAVE_AREA_OFFSET = 120 - _GAP REGISTERS_SAVED = [r.r25, r.r26, r.r27, r.r28, r.r29, r.r30, r.r31] assert REGISTERS_SAVED == [_r for _r in r.NONVOLATILES diff --git a/rpython/jit/backend/ppc/asmfunc.py b/rpython/jit/backend/ppc/asmfunc.py deleted file mode 100644 --- a/rpython/jit/backend/ppc/asmfunc.py +++ /dev/null @@ -1,39 +0,0 @@ -import py -import mmap, struct - -from rpython.jit.backend.ppc.codebuf import MachineCodeBlockWrapper -from rpython.jit.backend.llsupport.asmmemmgr import AsmMemoryManager -from rpython.rtyper.lltypesystem import lltype, rffi -from rpython.jit.backend.ppc.arch import IS_PPC_32, IS_PPC_64, WORD -from rpython.rlib.rarithmetic import r_uint - -_ppcgen = None - -def get_ppcgen(): - global _ppcgen - if _ppcgen is None: - _ppcgen = py.magic.autopath().dirpath().join('_ppcgen.c')._getpymodule() - return _ppcgen - -class AsmCode(object): - def __init__(self, size): - self.code = MachineCodeBlockWrapper() - if IS_PPC_64: - # allocate function descriptor - 3 doublewords - for i in range(6): - self.emit(r_uint(0)) - - def emit(self, word): - self.code.writechar(chr((word >> 24) & 0xFF)) - self.code.writechar(chr((word >> 16) & 0xFF)) - self.code.writechar(chr((word >> 8) & 0xFF)) - self.code.writechar(chr(word & 0xFF)) - - def get_function(self): - i = self.code.materialize(AsmMemoryManager(), []) - if IS_PPC_64: - p = rffi.cast(rffi.CArrayPtr(lltype.Signed), i) - p[0] = i + 3*WORD - # p[1], p[2] = ?? - t = lltype.FuncType([], lltype.Signed) - return rffi.cast(lltype.Ptr(t), i) diff --git a/rpython/jit/backend/ppc/callbuilder.py b/rpython/jit/backend/ppc/callbuilder.py --- a/rpython/jit/backend/ppc/callbuilder.py +++ b/rpython/jit/backend/ppc/callbuilder.py @@ -1,6 +1,7 @@ -from rpython.jit.backend.ppc.arch import IS_PPC_64, WORD +from rpython.jit.backend.ppc.arch import IS_PPC_64, WORD, PARAM_SAVE_AREA_OFFSET +from rpython.jit.backend.ppc.arch import IS_BIG_ENDIAN, IS_LITTLE_ENDIAN import rpython.jit.backend.ppc.register as r -from rpython.jit.metainterp.history import INT +from rpython.jit.metainterp.history import INT, FLOAT from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder from rpython.jit.backend.ppc.jump import remap_frame_layout @@ -11,6 +12,15 @@ class CallBuilder(AbstractCallBuilder): + GPR_ARGS = [r.r3, r.r4, r.r5, r.r6, r.r7, r.r8, r.r9, r.r10] + FPR_ARGS = r.MANAGED_FP_REGS + assert FPR_ARGS == [r.f1, r.f2, r.f3, r.f4, r.f5, r.f6, r.f7, + r.f8, r.f9, r.f10, r.f11, r.f12, r.f13] + + if IS_BIG_ENDIAN: + FNREG = r.r2 + else: + FNREG = r.r12 def __init__(self, assembler, fnloc, arglocs, resloc): AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, @@ -18,18 +28,73 @@ def prepare_arguments(self): assert IS_PPC_64 - - # First, copy fnloc into r2 - self.asm.regalloc_mov(self.fnloc, r.r2) + self.subtracted_to_sp = 0 # Prepare arguments arglocs = self.arglocs - argtypes = self.argtypes + num_args = len(arglocs) - assert len(argtypes) <= 8, "XXX" - non_float_locs = arglocs - non_float_regs = ( # XXX - [r.r3, r.r4, r.r5, r.r6, r.r7, r.r8, r.r9, r.r10][:len(argtypes)]) + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(min(num_args, 8)): + if arglocs[i].type != FLOAT: + non_float_locs.append(arglocs[i]) + non_float_regs.append(self.GPR_ARGS[i]) + else: + float_locs.append(arglocs[i]) + # now 'non_float_locs' and 'float_locs' together contain the + # locations of the first 8 arguments + + if num_args > 8: + # We need to make a larger PPC stack frame, as shown on the + # picture in arch.py. It needs to be 48 bytes + 8 * num_args. + # The new SP back chain location should point to the top of + # the whole stack frame, i.e. jumping over both the existing + # fixed-sise part and the new variable-sized part. + base = PARAM_SAVE_AREA_OFFSET + varsize = base + 8 * num_args + varsize = (varsize + 15) & ~15 # align + self.mc.load(r.SCRATCH2.value, r.SP.value, 0) # SP back chain + self.mc.store_update(r.SCRATCH2.value, r.SP.value, -varsize) + self.subtracted_to_sp = varsize + + # In this variable-sized part, only the arguments from the 8th + # one need to be written, starting at SP + 112 + for n in range(8, num_args): + loc = arglocs[n] + if loc.type != FLOAT: + # after the 8th argument, a non-float location is + # always stored in the stack + if loc.is_reg(): + src = loc.value + else: + src = r.r2 + self.asm.regalloc_mov(loc, src) + self.mc.std(src.value, r.SP.value, base + 8 * n) + else: + # the first 13 floating-point arguments are all passed + # in the registers f1 to f13, independently on their + # index in the complete list of arguments + if len(float_locs) < len(self.FPR_ARGS): + float_locs.append(loc) + else: + if loc.is_fp_reg(): + src = loc.value + else: + src = r.FP_SCRATCH + self.asm.regalloc_mov(loc, src) + self.mc.stfd(src.value, r.SP.value, base + 8 * n) + + # We must also copy fnloc into FNREG + non_float_locs.append(self.fnloc) + non_float_regs.append(self.FNREG) + + if float_locs: + assert len(float_locs) <= len(self.FPR_ARGS) + remap_frame_layout(self.asm, float_locs, + self.FPR_ARGS[:len(float_locs)], + r.FP_SCRATCH) remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.SCRATCH) @@ -42,19 +107,25 @@ pass # XXX def emit_raw_call(self): - # Load the function descriptor (currently in r2) from memory: - # [r2 + 0] -> ctr - # [r2 + 16] -> r11 - # [r2 + 8] -> r2 (= TOC) - self.mc.ld(r.SCRATCH.value, r.r2.value, 0) - self.mc.ld(r.r11.value, r.r2.value, 16) - self.mc.mtctr(r.SCRATCH.value) - self.mc.ld(r.TOC.value, r.r2.value, 8) - # Call it + if IS_BIG_ENDIAN: + # Load the function descriptor (currently in r2) from memory: + # [r2 + 0] -> ctr + # [r2 + 16] -> r11 + # [r2 + 8] -> r2 (= TOC) + assert self.FNREG is r.r2 + self.mc.ld(r.SCRATCH.value, r.r2.value, 0) + self.mc.ld(r.r11.value, r.r2.value, 16) + self.mc.mtctr(r.SCRATCH.value) + self.mc.ld(r.TOC.value, r.r2.value, 8) # must be last: TOC is r2 + elif IS_LITTLE_ENDIAN: + assert self.FNREG is r.r12 + self.mc.mtctr(r.r12.value) + # Call the function self.mc.bctrl() def restore_stack_pointer(self): - pass # XXX + if self.subtracted_to_sp != 0: + self.mc.addi(r.SP.value, r.SP.value, self.subtracted_to_sp) def load_result(self): pass diff --git a/rpython/jit/backend/ppc/codebuilder.py b/rpython/jit/backend/ppc/codebuilder.py --- a/rpython/jit/backend/ppc/codebuilder.py +++ b/rpython/jit/backend/ppc/codebuilder.py @@ -2,8 +2,8 @@ from rpython.jit.backend.ppc.ppc_form import PPCForm as Form from rpython.jit.backend.ppc.locations import RegisterLocation from rpython.jit.backend.ppc.ppc_field import ppc_fields -from rpython.jit.backend.ppc.arch import (IS_PPC_32, WORD, IS_PPC_64, - LR_BC_OFFSET) +from rpython.jit.backend.ppc.arch import (IS_PPC_32, WORD, IS_PPC_64, + LR_BC_OFFSET, IS_BIG_ENDIAN, IS_LITTLE_ENDIAN) import rpython.jit.backend.ppc.register as r import rpython.jit.backend.ppc.condition as c from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin @@ -944,10 +944,16 @@ def write32(self, word): index = self.index - self.mc.overwrite(index, chr((word >> 24) & 0xff)) - self.mc.overwrite(index + 1, chr((word >> 16) & 0xff)) - self.mc.overwrite(index + 2, chr((word >> 8) & 0xff)) - self.mc.overwrite(index + 3, chr(word & 0xff)) + if IS_BIG_ENDIAN: + self.mc.overwrite(index, chr((word >> 24) & 0xff)) + self.mc.overwrite(index + 1, chr((word >> 16) & 0xff)) + self.mc.overwrite(index + 2, chr((word >> 8) & 0xff)) + self.mc.overwrite(index + 3, chr(word & 0xff)) + elif IS_LITTLE_ENDIAN: + self.mc.overwrite(index , chr(word & 0xff)) + self.mc.overwrite(index + 1, chr((word >> 8) & 0xff)) + self.mc.overwrite(index + 2, chr((word >> 16) & 0xff)) + self.mc.overwrite(index + 3, chr((word >> 24) & 0xff)) self.index = index + 4 def overwrite(self): @@ -1031,42 +1037,42 @@ self.mtctr(r.SCRATCH.value) self.bctrl() - def call(self, address): - """ do a call to an absolute address - """ - with scratch_reg(self): - if IS_PPC_32: - self.load_imm(r.SCRATCH, address) - else: - self.store(r.TOC.value, r.SP.value, 5 * WORD) - self.load_imm(r.r11, address) - self.load(r.SCRATCH.value, r.r11.value, 0) - self.load(r.TOC.value, r.r11.value, WORD) - self.load(r.r11.value, r.r11.value, 2 * WORD) - self.mtctr(r.SCRATCH.value) - self.bctrl() + ## def call(self, address): + ## """ do a call to an absolute address + ## """ + ## with scratch_reg(self): + ## if IS_PPC_32: + ## self.load_imm(r.SCRATCH, address) + ## else: + ## self.store(r.TOC.value, r.SP.value, 5 * WORD) + ## self.load_imm(r.r11, address) + ## self.load(r.SCRATCH.value, r.r11.value, 0) + ## self.load(r.TOC.value, r.r11.value, WORD) + ## self.load(r.r11.value, r.r11.value, 2 * WORD) + ## self.mtctr(r.SCRATCH.value) + ## self.bctrl() - if IS_PPC_64: - self.load(r.TOC.value, r.SP.value, 5 * WORD) + ## if IS_PPC_64: + ## self.load(r.TOC.value, r.SP.value, 5 * WORD) - def call_register(self, call_reg): - """ do a call to an address given in a register - """ - assert isinstance(call_reg, RegisterLocation) - with scratch_reg(self): - if IS_PPC_32: - self.mr(r.SCRATCH.value, call_reg.value) - else: - self.store(r.TOC.value, r.SP.value, 5 * WORD) - self.mr(r.r11.value, call_reg.value) - self.load(r.SCRATCH.value, r.r11.value, 0) - self.load(r.TOC.value, r.r11.value, WORD) - self.load(r.r11.value, r.r11.value, 2 * WORD) - self.mtctr(r.SCRATCH.value) - self.bctrl() + ## def call_register(self, call_reg): + ## """ do a call to an address given in a register + ## """ + ## assert isinstance(call_reg, RegisterLocation) + ## with scratch_reg(self): + ## if IS_PPC_32: + ## self.mr(r.SCRATCH.value, call_reg.value) + ## else: + ## self.store(r.TOC.value, r.SP.value, 5 * WORD) + ## self.mr(r.r11.value, call_reg.value) + ## self.load(r.SCRATCH.value, r.r11.value, 0) + ## self.load(r.TOC.value, r.r11.value, WORD) + ## self.load(r.r11.value, r.r11.value, 2 * WORD) + ## self.mtctr(r.SCRATCH.value) + ## self.bctrl() - if IS_PPC_64: - self.load(r.TOC.value, r.SP.value, 5 * WORD) + ## if IS_PPC_64: + ## self.load(r.TOC.value, r.SP.value, 5 * WORD) ## def make_function_prologue(self, frame_size): ## """ Build a new stackframe of size frame_size @@ -1140,20 +1146,36 @@ f.close() def write32(self, word): - self.writechar(chr((word >> 24) & 0xFF)) - self.writechar(chr((word >> 16) & 0xFF)) - self.writechar(chr((word >> 8) & 0xFF)) - self.writechar(chr(word & 0xFF)) + if IS_BIG_ENDIAN: + self.writechar(chr((word >> 24) & 0xFF)) + self.writechar(chr((word >> 16) & 0xFF)) + self.writechar(chr((word >> 8) & 0xFF)) + self.writechar(chr(word & 0xFF)) + elif IS_LITTLE_ENDIAN: + self.writechar(chr(word & 0xFF)) + self.writechar(chr((word >> 8) & 0xFF)) + self.writechar(chr((word >> 16) & 0xFF)) + self.writechar(chr((word >> 24) & 0xFF)) def write64(self, word): - self.writechar(chr((word >> 56) & 0xFF)) - self.writechar(chr((word >> 48) & 0xFF)) - self.writechar(chr((word >> 40) & 0xFF)) - self.writechar(chr((word >> 32) & 0xFF)) - self.writechar(chr((word >> 24) & 0xFF)) - self.writechar(chr((word >> 16) & 0xFF)) - self.writechar(chr((word >> 8) & 0xFF)) - self.writechar(chr(word & 0xFF)) + if IS_BIG_ENDIAN: + self.writechar(chr((word >> 56) & 0xFF)) + self.writechar(chr((word >> 48) & 0xFF)) + self.writechar(chr((word >> 40) & 0xFF)) + self.writechar(chr((word >> 32) & 0xFF)) + self.writechar(chr((word >> 24) & 0xFF)) + self.writechar(chr((word >> 16) & 0xFF)) + self.writechar(chr((word >> 8) & 0xFF)) + self.writechar(chr(word & 0xFF)) + elif IS_LITTLE_ENDIAN: + self.writechar(chr(word & 0xFF)) + self.writechar(chr((word >> 8) & 0xFF)) + self.writechar(chr((word >> 16) & 0xFF)) + self.writechar(chr((word >> 24) & 0xFF)) + self.writechar(chr((word >> 32) & 0xFF)) + self.writechar(chr((word >> 40) & 0xFF)) + self.writechar(chr((word >> 48) & 0xFF)) + self.writechar(chr((word >> 56) & 0xFF)) def currpos(self): return self.get_relative_pos() diff --git a/rpython/jit/backend/ppc/opassembler.py b/rpython/jit/backend/ppc/opassembler.py --- a/rpython/jit/backend/ppc/opassembler.py +++ b/rpython/jit/backend/ppc/opassembler.py @@ -5,7 +5,8 @@ from rpython.jit.backend.ppc.locations import imm from rpython.jit.backend.ppc.locations import imm as make_imm_loc from rpython.jit.backend.ppc.arch import (IS_PPC_32, IS_PPC_64, WORD, - MAX_REG_PARAMS, MAX_FREG_PARAMS) + MAX_REG_PARAMS, MAX_FREG_PARAMS, + PARAM_SAVE_AREA_OFFSET) from rpython.jit.metainterp.history import (JitCellToken, TargetToken, Box, AbstractFailDescr, FLOAT, INT, REF) @@ -232,24 +233,24 @@ def emit_cast_float_to_int(self, op, arglocs, regalloc): l0, temp_loc, res = arglocs self.mc.fctidz(temp_loc.value, l0.value) - self.mc.stfd(temp_loc.value, r.SP.value, -16) - self.mc.ld(res.value, r.SP.value, -16) + self.mc.stfd(temp_loc.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) + self.mc.ld(res.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) def emit_cast_int_to_float(self, op, arglocs, regalloc): l0, res = arglocs - self.mc.std(l0.value, r.SP.value, -16) - self.mc.lfd(res.value, r.SP.value, -16) + self.mc.std(l0.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) + self.mc.lfd(res.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) self.mc.fcfid(res.value, res.value) def emit_convert_float_bytes_to_longlong(self, op, arglocs, regalloc): l0, res = arglocs - self.mc.stfd(l0.value, r.SP.value, -16) - self.mc.ld(res.value, r.SP.value, -16) + self.mc.stfd(l0.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) + self.mc.ld(res.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) def emit_convert_longlong_bytes_to_float(self, op, arglocs, regalloc): l0, res = arglocs - self.mc.std(l0.value, r.SP.value, -16) - self.mc.lfd(res.value, r.SP.value, -16) + self.mc.std(l0.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) + self.mc.lfd(res.value, r.SP.value, PARAM_SAVE_AREA_OFFSET) class GuardOpAssembler(object): diff --git a/rpython/jit/backend/ppc/ppc_assembler.py b/rpython/jit/backend/ppc/ppc_assembler.py --- a/rpython/jit/backend/ppc/ppc_assembler.py +++ b/rpython/jit/backend/ppc/ppc_assembler.py @@ -7,7 +7,8 @@ LR_BC_OFFSET, REGISTERS_SAVED, GPR_SAVE_AREA_OFFSET, THREADLOCAL_ADDR_OFFSET, - STD_FRAME_SIZE_IN_BYTES) + STD_FRAME_SIZE_IN_BYTES, + IS_BIG_ENDIAN) from rpython.jit.backend.ppc.helper.assembler import Saved_Volatiles from rpython.jit.backend.ppc.helper.regalloc import _check_imm_arg import rpython.jit.backend.ppc.register as r @@ -354,9 +355,9 @@ frame_size += WORD # write function descriptor - if IS_PPC_64: - for _ in range(6): - mc.write32(0) + if IS_PPC_64 and IS_BIG_ENDIAN: + for _ in range(3): + mc.write64(0) # build frame mc.make_function_prologue(frame_size) @@ -550,7 +551,7 @@ # self.mc.b_offset(loophead) def _call_header(self): - if IS_PPC_64: + if IS_PPC_64 and IS_BIG_ENDIAN: # Reserve space for a function descriptor, 3 words self.mc.write64(0) self.mc.write64(0) @@ -717,7 +718,7 @@ full_size = self.mc.get_relative_pos() # rawstart = self.materialize_loop(looptoken) - if IS_PPC_64: # fix the function descriptor (3 words) + if IS_PPC_64 and IS_BIG_ENDIAN: # fix the function descriptor (3 words) rffi.cast(rffi.LONGP, rawstart)[0] = rawstart + 3 * WORD # self.patch_stack_checks(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE, @@ -788,6 +789,7 @@ self.current_clt.allgcrefs, self.current_clt.frame_info) #self._check_frame_depth(self.mc, regalloc.get_gcmap()) + # XXX ^^^^^^^^^^ frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, operations) codeendpos = self.mc.get_relative_pos() self.write_pending_failure_recoveries() diff --git a/rpython/jit/backend/ppc/test/test_runner.py b/rpython/jit/backend/ppc/test/test_runner.py --- a/rpython/jit/backend/ppc/test/test_runner.py +++ b/rpython/jit/backend/ppc/test/test_runner.py @@ -202,3 +202,37 @@ assert fail.identifier == 5 res = self.cpu.get_int_value(deadframe, 0) assert res == -42 + NUM + + def test_call_many_float_args(self): + from rpython.rtyper.annlowlevel import llhelper + from rpython.jit.codewriter.effectinfo import EffectInfo + + seen = [] + def func(*args): + seen.append(args) + return -42 + + F = lltype.Float + I = lltype.Signed + FUNC = self.FuncType([F] * 7 + [I] + [F] * 7 + [I] + [F], I) + FPTR = self.Ptr(FUNC) + func_ptr = llhelper(FPTR, func) + cpu = self.cpu + calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, + EffectInfo.MOST_GENERAL) + funcbox = self.get_funcbox(cpu, func_ptr) + argvals = [.1 * i for i in range(15)] + argvals.insert(7, 77) + argvals.insert(15, 1515) + argvals = tuple(argvals) + argboxes = [] + for x in argvals: + if isinstance(x, float): + argboxes.append(BoxFloat(x)) + else: + argboxes.append(BoxInt(x)) + res = self.execute_operation(rop.CALL, + [funcbox] + argboxes, + 'int', descr=calldescr) + assert res.value == -42 + assert seen == [argvals] diff --git a/rpython/jit/backend/tool/viewcode.py b/rpython/jit/backend/tool/viewcode.py --- a/rpython/jit/backend/tool/viewcode.py +++ b/rpython/jit/backend/tool/viewcode.py @@ -56,7 +56,9 @@ } cmd = find_objdump() objdump = ('%(command)s -b binary -m %(machine)s ' - '--endian=%(endianness)s ' + # NOTE: specifying endianness is annoying to debug the ppc + # backend on little-endian machines; better use the native one + #'--endian=%(endianness)s ' '--disassembler-options=intel-mnemonics ' '--adjust-vma=%(origin)d -D %(file)s') # From noreply at buildbot.pypy.org Fri Sep 11 15:22:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 11 Sep 2015 15:22:43 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: PPC Backend #3: fix the calls. Message-ID: <20150911132243.B2A9F1C11E0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79592:5b7660b90e96 Date: 2015-09-05 18:35 +0200 http://bitbucket.org/pypy/pypy/changeset/5b7660b90e96/ Log: PPC Backend #3: fix the calls. Reviewed the particular calling conventions and adapted to them. Copy and adapt callbuilder.py from the x86 backend. Add support for releasing the GIL, saving and restoring errno, and so on. diff too long, truncating to 2000 out of 2077 lines diff --git a/rpython/jit/backend/llsupport/llerrno.py b/rpython/jit/backend/llsupport/llerrno.py --- a/rpython/jit/backend/llsupport/llerrno.py +++ b/rpython/jit/backend/llsupport/llerrno.py @@ -1,14 +1,22 @@ +import sys from rpython.rtyper.lltypesystem import lltype, rffi from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.jit.backend.llsupport.symbolic import WORD +if sys.byteorder == 'little' or sys.maxint <= 2**32: + long2int = int2long = lambda x: x +else: + def long2int(x): return x >> 32 + def int2long(x): return x << 32 + + def get_debug_saved_errno(cpu): - return cpu._debug_errno_container[3] + return long2int(cpu._debug_errno_container[3]) def set_debug_saved_errno(cpu, nerrno): assert nerrno >= 0 - cpu._debug_errno_container[3] = nerrno + cpu._debug_errno_container[3] = int2long(nerrno) def get_rpy_errno_offset(cpu): if cpu.translate_support_code: @@ -19,11 +27,11 @@ def get_debug_saved_alterrno(cpu): - return cpu._debug_errno_container[4] + return long2int(cpu._debug_errno_container[4]) def set_debug_saved_alterrno(cpu, nerrno): assert nerrno >= 0 - cpu._debug_errno_container[4] = nerrno + cpu._debug_errno_container[4] = int2long(nerrno) def get_alt_errno_offset(cpu): if cpu.translate_support_code: diff --git a/rpython/jit/backend/ppc/callbuilder.py b/rpython/jit/backend/ppc/callbuilder.py --- a/rpython/jit/backend/ppc/callbuilder.py +++ b/rpython/jit/backend/ppc/callbuilder.py @@ -1,9 +1,12 @@ from rpython.jit.backend.ppc.arch import IS_PPC_64, WORD, PARAM_SAVE_AREA_OFFSET -from rpython.jit.backend.ppc.arch import IS_BIG_ENDIAN, IS_LITTLE_ENDIAN +from rpython.jit.backend.ppc.arch import THREADLOCAL_ADDR_OFFSET import rpython.jit.backend.ppc.register as r from rpython.jit.metainterp.history import INT, FLOAT from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder from rpython.jit.backend.ppc.jump import remap_frame_layout +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.backend.llsupport import llerrno +from rpython.rtyper.lltypesystem import rffi def follow_jump(addr): @@ -16,11 +19,9 @@ FPR_ARGS = r.MANAGED_FP_REGS assert FPR_ARGS == [r.f1, r.f2, r.f3, r.f4, r.f5, r.f6, r.f7, r.f8, r.f9, r.f10, r.f11, r.f12, r.f13] - - if IS_BIG_ENDIAN: - FNREG = r.r2 - else: - FNREG = r.r12 + RSHADOWPTR = r.RCS1 + RFASTGILPTR = r.RCS2 + RSHADOWOLD = r.RCS3 def __init__(self, assembler, fnloc, arglocs, resloc): AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, @@ -30,7 +31,16 @@ assert IS_PPC_64 self.subtracted_to_sp = 0 - # Prepare arguments + # Prepare arguments. Note that this follows the convention where + # a prototype is in scope, and doesn't take "..." arguments. If + # you were to call a C function with a "..." argument with cffi, + # it would not go there but instead via libffi. If you pretend + # instead that it takes fixed arguments, then it would arrive here + # but the convention is bogus for floating-point arguments. (And, + # to add to the mess, at least CPython's ctypes cannot be used + # to call a "..." function with floating-point arguments. As I + # guess that it's a problem with libffi, it means PyPy inherits + # the same problem.) arglocs = self.arglocs num_args = len(arglocs) @@ -67,7 +77,7 @@ # after the 8th argument, a non-float location is # always stored in the stack if loc.is_reg(): - src = loc.value + src = loc else: src = r.r2 self.asm.regalloc_mov(loc, src) @@ -80,7 +90,7 @@ float_locs.append(loc) else: if loc.is_fp_reg(): - src = loc.value + src = loc else: src = r.FP_SCRATCH self.asm.regalloc_mov(loc, src) @@ -88,7 +98,7 @@ # We must also copy fnloc into FNREG non_float_locs.append(self.fnloc) - non_float_regs.append(self.FNREG) + non_float_regs.append(self.mc.RAW_CALL_REG) # r2 or r12 if float_locs: assert len(float_locs) <= len(self.FPR_ARGS) @@ -107,25 +117,145 @@ pass # XXX def emit_raw_call(self): - if IS_BIG_ENDIAN: - # Load the function descriptor (currently in r2) from memory: - # [r2 + 0] -> ctr - # [r2 + 16] -> r11 - # [r2 + 8] -> r2 (= TOC) - assert self.FNREG is r.r2 - self.mc.ld(r.SCRATCH.value, r.r2.value, 0) - self.mc.ld(r.r11.value, r.r2.value, 16) - self.mc.mtctr(r.SCRATCH.value) - self.mc.ld(r.TOC.value, r.r2.value, 8) # must be last: TOC is r2 - elif IS_LITTLE_ENDIAN: - assert self.FNREG is r.r12 - self.mc.mtctr(r.r12.value) - # Call the function - self.mc.bctrl() + self.mc.raw_call() def restore_stack_pointer(self): if self.subtracted_to_sp != 0: self.mc.addi(r.SP.value, r.SP.value, self.subtracted_to_sp) def load_result(self): - pass + assert (self.resloc is None or + self.resloc is r.r3 or + self.resloc is r.f1) + + + def call_releasegil_addr_and_move_real_arguments(self, fastgil): + assert self.is_call_release_gil + RSHADOWPTR = self.RSHADOWPTR + RFASTGILPTR = self.RFASTGILPTR + RSHADOWOLD = self.RSHADOWOLD + # + # Save this thread's shadowstack pointer into r29, for later comparison + gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + rst = gcrootmap.get_root_stack_top_addr() + self.mc.load_imm(RSHADOWPTR, rst) + self.mc.load(RSHADOWOLD.value, RSHADOWPTR.value, 0) + # + # change 'rpy_fastgil' to 0 (it should be non-zero right now) + self.mc.load_imm(RFASTGILPTR, fastgil) + self.mc.li(r.r0.value, 0) + self.mc.lwsync() + self.mc.std(r.r0.value, RFASTGILPTR.value, 0) + # + if not we_are_translated(): # for testing: we should not access + self.mc.addi(r.SPP.value, r.SPP.value, 1) # r31 any more + + + def move_real_result_and_call_reacqgil_addr(self, fastgil): + from rpython.jit.backend.ppc.codebuilder import OverwritingBuilder + + # try to reacquire the lock. The following registers are still + # valid from before the call: + RSHADOWPTR = self.RSHADOWPTR # r30: &root_stack_top + RFASTGILPTR = self.RFASTGILPTR # r29: &fastgil + RSHADOWOLD = self.RSHADOWOLD # r28: previous val of root_stack_top + + # Equivalent of 'r10 = __sync_lock_test_and_set(&rpy_fastgil, 1);' + self.mc.li(r.r9.value, 1) + retry_label = self.mc.currpos() + self.mc.ldarx(r.r10.value, 0, RFASTGILPTR.value) # load the lock value + self.mc.stdcxx(r.r9.value, 0, RFASTGILPTR.value) # try to claim lock + self.mc.bc(6, 2, retry_label - self.mc.currpos()) # retry if failed + self.mc.isync() + + self.mc.cmpdi(0, r.r10.value, 0) + b1_location = self.mc.currpos() + self.mc.trap() # patched with a BEQ: jump if r10 is zero + + if self.asm.cpu.gc_ll_descr.gcrootmap: + # When doing a call_release_gil with shadowstack, there + # is the risk that the 'rpy_fastgil' was free but the + # current shadowstack can be the one of a different + # thread. So here we check if the shadowstack pointer + # is still the same as before we released the GIL (saved + # in 'r7'), and if not, we fall back to 'reacqgil_addr'. + XXXXXXXXXXXXXXXXXXX + self.mc.LDR_ri(r.ip.value, r.r5.value, cond=c.EQ) + self.mc.CMP_rr(r.ip.value, r.r7.value, cond=c.EQ) + b1_location = self.mc.currpos() + self.mc.BKPT() # BEQ below + # there are two cases here: either EQ was false from + # the beginning, or EQ was true at first but the CMP + # made it false. In the second case we need to + # release the fastgil here. We know which case it is + # by checking again r3. + self.mc.CMP_ri(r.r3.value, 0) + self.mc.STR_ri(r.r3.value, r.r6.value, cond=c.EQ) + # + # save the result we just got + RSAVEDRES = RFASTGILPTR # can reuse this reg here + reg = self.resloc + if reg is not None: + if reg.is_core_reg(): + self.mc.mr(RSAVEDRES.value, reg.value) + elif reg.is_fp_reg(): + self.mc.stfd(reg.value, r.SP.value, + PARAM_SAVE_AREA_OFFSET + 7 * WORD) + self.mc.load_imm(self.mc.RAW_CALL_REG, self.asm.reacqgil_addr) + self.mc.raw_call() + if reg is not None: + if reg.is_core_reg(): + self.mc.mr(reg.value, RSAVEDRES.value) + elif reg.is_fp_reg(): + self.mc.lfd(reg.value, r.SP.value, + PARAM_SAVE_AREA_OFFSET + 7 * WORD) + + # replace b1_location with BEQ(here) + jmp_target = self.mc.currpos() + pmc = OverwritingBuilder(self.mc, b1_location, 1) + pmc.bc(12, 2, jmp_target - b1_location) # "beq" + pmc.overwrite() + + if not we_are_translated(): # for testing: now we can access + self.mc.addi(r.SPP.value, r.SPP.value, -1) # r31 again + + + def write_real_errno(self, save_err): + if save_err & rffi.RFFI_READSAVED_ERRNO: + # Just before a call, read '*_errno' and write it into the + # real 'errno'. A lot of registers are free here, notably + # r11 and r0. + if save_err & rffi.RFFI_ALT_ERRNO: + rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu) + else: + rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu) + p_errno = llerrno.get_p_errno_offset(self.asm.cpu) + self.mc.ld(r.r11.value, r.SP.value, + THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp) + self.mc.lwz(r.r0.value, r.r11.value, rpy_errno) + self.mc.ld(r.r11.value, r.r11.value, p_errno) + self.mc.stw(r.r0.value, r.r11.value, 0) + elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE: + # Same, but write zero. + p_errno = llerrno.get_p_errno_offset(self.asm.cpu) + self.mc.ld(r.r11.value, r.SP.value, + THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp) + self.mc.ld(r.r11.value, r.r11.value, p_errno) + self.mc.li(r.r0.value, 0) + self.mc.stw(r.r0.value, r.r11.value, 0) + + def read_real_errno(self, save_err): + if save_err & rffi.RFFI_SAVE_ERRNO: + # Just after a call, read the real 'errno' and save a copy of + # it inside our thread-local '*_errno'. Registers r4-r10 + # never contain anything after the call. + if save_err & rffi.RFFI_ALT_ERRNO: + rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu) + else: + rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu) + p_errno = llerrno.get_p_errno_offset(self.asm.cpu) + self.mc.ld(r.r9.value, r.SP.value, THREADLOCAL_ADDR_OFFSET) + self.mc.ld(r.r10.value, r.r9.value, p_errno) + self.mc.lwz(r.r10.value, r.r10.value, 0) + self.mc.stw(r.r10.value, r.r9.value, rpy_errno) diff --git a/rpython/jit/backend/ppc/codebuilder.py b/rpython/jit/backend/ppc/codebuilder.py --- a/rpython/jit/backend/ppc/codebuilder.py +++ b/rpython/jit/backend/ppc/codebuilder.py @@ -47,6 +47,7 @@ XL2 = Form("crbD", "XO1", "Rc") XFL = Form("FM", "frB", "XO1", "Rc") XFX = Form("CRM", "rS", "XO1") +XLL = Form("LL", "XO1") MI = Form("rA", "rS", "SH", "MB", "ME", "Rc") MB = Form("rA", "rS", "rB", "MB", "ME", "Rc") @@ -542,7 +543,8 @@ subfzeo = XO0(31, OE=1, XO2=200, Rc=0) subfzeox= XO0(31, OE=1, XO2=200, Rc=1) - sync = X(31, XO1=598) + sync = XLL(31, LL=0, XO1=598) + lwsync = XLL(31, LL=1, XO1=598) tlbia = X(31, XO1=370) tlbie = Form("rB", "XO1")(31, XO1=306) @@ -925,8 +927,8 @@ class PPCGuardToken(GuardToken): def __init__(self, cpu, gcmap, descr, failargs, faillocs, exc, frame_depth, is_guard_not_invalidated=False, - is_guard_not_forced=False, fcond=c.UH): - assert fcond != c.UH + is_guard_not_forced=False, fcond=c.cond_none): + assert fcond != c.cond_none GuardToken.__init__(self, cpu, gcmap, descr, failargs, faillocs, exc, frame_depth, is_guard_not_invalidated, is_guard_not_forced) @@ -1007,7 +1009,7 @@ self.b(offset) def b_cond_offset(self, offset, condition): - assert condition != c.UH + assert condition != c.cond_none BI, BO = c.encoding[condition] pos = self.currpos() @@ -1015,7 +1017,7 @@ self.bc(BO, BI, target_ofs) def b_cond_abs(self, addr, condition): - assert condition != c.UH + assert condition != c.cond_none BI, BO = c.encoding[condition] with scratch_reg(self): @@ -1037,6 +1039,29 @@ self.mtctr(r.SCRATCH.value) self.bctrl() + if IS_BIG_ENDIAN: + RAW_CALL_REG = r.r2 + else: + RAW_CALL_REG = r.r12 + + def raw_call(self): + """Emit a call to the address stored in the register RAW_CALL_REG.""" + if IS_BIG_ENDIAN: + # Load the function descriptor (currently in r2) from memory: + # [r2 + 0] -> ctr + # [r2 + 16] -> r11 + # [r2 + 8] -> r2 (= TOC) + assert self.RAW_CALL_REG is r.r2 + self.ld(r.SCRATCH.value, r.r2.value, 0) + self.ld(r.r11.value, r.r2.value, 16) + self.mtctr(r.SCRATCH.value) + self.ld(r.TOC.value, r.r2.value, 8) # must be last: TOC is r2 + elif IS_LITTLE_ENDIAN: + assert self.RAW_CALL_REG is r.r12 # 'r12' is fixed by this ABI + self.mtctr(r.r12.value) + # Call the function + self.bctrl() + ## def call(self, address): ## """ do a call to an absolute address ## """ diff --git a/rpython/jit/backend/ppc/condition.py b/rpython/jit/backend/ppc/condition.py --- a/rpython/jit/backend/ppc/condition.py +++ b/rpython/jit/backend/ppc/condition.py @@ -6,7 +6,7 @@ GE = 5 SO = 6 NS = 7 -UH = -1 # invalid +cond_none = -1 # invalid def negate(cond): return cond ^ 1 diff --git a/rpython/jit/backend/ppc/helper/assembler.py b/rpython/jit/backend/ppc/helper/assembler.py --- a/rpython/jit/backend/ppc/helper/assembler.py +++ b/rpython/jit/backend/ppc/helper/assembler.py @@ -6,15 +6,36 @@ import rpython.jit.backend.ppc.register as r from rpython.rtyper.lltypesystem import rffi, lltype -def test_condition_for(condition, guard_op): - opnum = guard_op.getopnum() - if opnum == rop.GUARD_FALSE: - return condition - elif opnum == rop.GUARD_TRUE: - return c.negate(condition) - assert 0, opnum -def do_emit_cmp_op(self, guard_op, arglocs, condition, signed, fp): +def flush_cc(asm, condition, result_loc): + # After emitting an instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to SPP by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert asm.guard_success_cc == c.cond_none + if result_loc is r.SPP: + asm.guard_success_cc = condition + else: + # Possibly invert the bit in the CR + bit, invert = c.encoding[condition] + assert 0 <= bit <= 3 + if invert == 12: + pass + elif invert == 4: + asm.mc.crnor(bit, bit, bit) + else: + assert 0 + + resval = result_loc.value + # move the content of the CR to resval + asm.mc.mfcr(resval) + # zero out everything except of the result + asm.mc.rlwinm(resval, resval, 1 + bit, 31, 31) + + +def do_emit_cmp_op(self, arglocs, condition, signed, fp): l0 = arglocs[0] l1 = arglocs[1] assert not l0.is_imm() @@ -40,32 +61,12 @@ self.mc.crnor(0, 0, 3) condition = c.LT - if guard_op is None: - # After the comparison, place the result in a single bit of the CR - bit, invert = c.encoding[condition] - assert 0 <= bit <= 3 - if invert == 12: - pass - elif invert == 4: - self.mc.crnor(bit, bit, bit) - else: - assert 0 + flush_cc(self, condition, arglocs[2]) - assert len(arglocs) == 3 - res = arglocs[2] - resval = res.value - # move the content of the CR to resval - self.mc.mfcr(resval) - # zero out everything except of the result - self.mc.rlwinm(resval, resval, 1 + bit, 31, 31) - else: - failargs = arglocs[2:] - fcond = test_condition_for(condition, guard_op) - self._emit_guard(guard_op, failargs, fcond) def gen_emit_cmp_op(condition, signed=True, fp=False): - def f(self, op, guard_op, arglocs, regalloc): - do_emit_cmp_op(self, guard_op, arglocs, condition, signed, fp) + def f(self, op, arglocs, regalloc): + do_emit_cmp_op(self, arglocs, condition, signed, fp) return f def count_reg_args(args): diff --git a/rpython/jit/backend/ppc/helper/regalloc.py b/rpython/jit/backend/ppc/helper/regalloc.py --- a/rpython/jit/backend/ppc/helper/regalloc.py +++ b/rpython/jit/backend/ppc/helper/regalloc.py @@ -13,7 +13,7 @@ def _prepare_cmp_op(signed): lower_bound = -2**15 if signed else 0 upper_bound = 2**15-1 if signed else 2**16-1 - def f(self, op, guard_op): + def f(self, op): l0 = self.ensure_reg(op.getarg(0)) a1 = op.getarg(1) if check_imm_box(a1, lower_bound, upper_bound): @@ -21,34 +21,25 @@ else: l1 = self.ensure_reg(a1) self.free_op_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - return self._prepare_guard(guard_op, [l0, l1]) + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] return f prepare_cmp_op = _prepare_cmp_op(signed=True) prepare_cmp_op_unsigned = _prepare_cmp_op(signed=False) -def prepare_unary_cmp(self, op, guard_op): +def prepare_unary_cmp(self, op): l0 = self.ensure_reg(op.getarg(0)) l1 = imm(0) self.free_op_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - return self._prepare_guard(guard_op, [l0, l1]) + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] -def prepare_float_cmp(self, op, guard_op): +def prepare_float_cmp(self, op): l0 = self.ensure_reg(op.getarg(0)) l1 = self.ensure_reg(op.getarg(1)) self.free_op_vars() - if guard_op is None: - res = self.force_allocate_reg(op.result) - return [l0, l1, res] - else: - return self._prepare_guard(guard_op, [l0, l1]) + res = self.force_allocate_reg_or_cc(op.result) + return [l0, l1, res] def prepare_unary_op(self, op): l0 = self.ensure_reg(op.getarg(0)) @@ -87,11 +78,3 @@ self.free_op_vars() res = self.force_allocate_reg(op.result) return [l0, l1, res] - -def prepare_int_binary_ovf(self, op, guard_op): - reg1 = self.ensure_reg(op.getarg(0)) - reg2 = self.ensure_reg(op.getarg(1)) - self.free_op_vars() - res = self.force_allocate_reg(op.result) - assert guard_op is not None - return self._prepare_guard(guard_op, [reg1, reg2, res]) diff --git a/rpython/jit/backend/ppc/jump.py b/rpython/jit/backend/ppc/jump.py --- a/rpython/jit/backend/ppc/jump.py +++ b/rpython/jit/backend/ppc/jump.py @@ -51,7 +51,7 @@ dst = dst_locations[i] originalkey = dst.as_key() if srccount[originalkey] >= 0: - assembler.regalloc_push(dst) + assembler.regalloc_push(dst, 0) while True: key = dst.as_key() assert srccount[key] == 1 @@ -63,7 +63,7 @@ break _move(assembler, src, dst, tmpreg) dst = src - assembler.regalloc_pop(dst) + assembler.regalloc_pop(dst, 0) assert pending_dests == 0 def _move(assembler, src, dst, tmpreg): @@ -91,7 +91,7 @@ key = loc.as_key() if (key in dst_keys or (loc.width > WORD and (key + 1) in dst_keys)): - assembler.regalloc_push(loc) + assembler.regalloc_push(loc, len(extrapushes)) extrapushes.append(dstloc) continue src_locations2red.append(loc) @@ -108,4 +108,4 @@ # finally, pop the extra fp stack locations while len(extrapushes) > 0: loc = extrapushes.pop() - assembler.regalloc_pop(loc) + assembler.regalloc_pop(loc, len(extrapushes)) diff --git a/rpython/jit/backend/ppc/opassembler.py b/rpython/jit/backend/ppc/opassembler.py --- a/rpython/jit/backend/ppc/opassembler.py +++ b/rpython/jit/backend/ppc/opassembler.py @@ -20,6 +20,7 @@ from rpython.jit.backend.llsupport.descr import InteriorFieldDescr, CallDescr from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.rtyper.lltypesystem import rstr, rffi, lltype +from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.ppc import callbuilder @@ -53,34 +54,23 @@ else: self.mc.mulld(res.value, l0.value, l1.value) - def do_emit_int_binary_ovf(self, op, guard_op, arglocs, emit): + def do_emit_int_binary_ovf(self, op, arglocs, emit): l0, l1, res = arglocs[0], arglocs[1], arglocs[2] self.mc.load_imm(r.SCRATCH, 0) self.mc.mtxer(r.SCRATCH.value) emit(res.value, l0.value, l1.value) - # - failargs = arglocs[3:] - assert guard_op is not None - opnum = guard_op.getopnum() - if opnum == rop.GUARD_NO_OVERFLOW: - fcond = c.SO - elif opnum == rop.GUARD_OVERFLOW: - fcond = c.NS + + def emit_int_add_ovf(self, op, arglocs, regalloc): + self.do_emit_int_binary_ovf(op, arglocs, self.mc.addox) + + def emit_int_sub_ovf(self, op, arglocs, regalloc): + self.do_emit_int_binary_ovf(op, arglocs, self.mc.subox) + + def emit_int_mul_ovf(self, op, arglocs, regalloc): + if IS_PPC_32: + self.do_emit_int_binary_ovf(op, arglocs, self.mc.mullwox) else: - assert 0 - self._emit_guard(guard_op, failargs, fcond) - - def emit_guard_int_add_ovf(self, op, guard_op, arglocs, regalloc): - self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.addox) - - def emit_guard_int_sub_ovf(self, op, guard_op, arglocs, regalloc): - self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.subox) - - def emit_guard_int_mul_ovf(self, op, guard_op, arglocs, regalloc): - if IS_PPC_32: - self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.mullwox) - else: - self.do_emit_int_binary_ovf(op, guard_op, arglocs, self.mc.mulldox) + self.do_emit_int_binary_ovf(op, arglocs, self.mc.mulldox) def emit_int_floordiv(self, op, arglocs, regalloc): l0, l1, res = arglocs @@ -140,26 +130,26 @@ else: self.mc.divdu(res.value, l0.value, l1.value) - emit_guard_int_le = gen_emit_cmp_op(c.LE) - emit_guard_int_lt = gen_emit_cmp_op(c.LT) - emit_guard_int_gt = gen_emit_cmp_op(c.GT) - emit_guard_int_ge = gen_emit_cmp_op(c.GE) - emit_guard_int_eq = gen_emit_cmp_op(c.EQ) - emit_guard_int_ne = gen_emit_cmp_op(c.NE) + emit_int_le = gen_emit_cmp_op(c.LE) + emit_int_lt = gen_emit_cmp_op(c.LT) + emit_int_gt = gen_emit_cmp_op(c.GT) + emit_int_ge = gen_emit_cmp_op(c.GE) + emit_int_eq = gen_emit_cmp_op(c.EQ) + emit_int_ne = gen_emit_cmp_op(c.NE) - emit_guard_uint_lt = gen_emit_cmp_op(c.LT, signed=False) - emit_guard_uint_le = gen_emit_cmp_op(c.LE, signed=False) - emit_guard_uint_gt = gen_emit_cmp_op(c.GT, signed=False) - emit_guard_uint_ge = gen_emit_cmp_op(c.GE, signed=False) + emit_uint_lt = gen_emit_cmp_op(c.LT, signed=False) + emit_uint_le = gen_emit_cmp_op(c.LE, signed=False) + emit_uint_gt = gen_emit_cmp_op(c.GT, signed=False) + emit_uint_ge = gen_emit_cmp_op(c.GE, signed=False) - emit_guard_int_is_zero = emit_guard_int_eq # EQ to 0 - emit_guard_int_is_true = emit_guard_int_ne # NE to 0 + emit_int_is_zero = emit_int_eq # EQ to 0 + emit_int_is_true = emit_int_ne # NE to 0 - emit_guard_ptr_eq = emit_guard_int_eq - emit_guard_ptr_ne = emit_guard_int_ne + emit_ptr_eq = emit_int_eq + emit_ptr_ne = emit_int_ne - emit_guard_instance_ptr_eq = emit_guard_ptr_eq - emit_guard_instance_ptr_ne = emit_guard_ptr_ne + emit_instance_ptr_eq = emit_ptr_eq + emit_instance_ptr_ne = emit_ptr_ne def emit_int_neg(self, op, arglocs, regalloc): l0, res = arglocs @@ -223,12 +213,12 @@ l0, res = arglocs self.mc.fsqrt(res.value, l0.value) - emit_guard_float_le = gen_emit_cmp_op(c.LE, fp=True) - emit_guard_float_lt = gen_emit_cmp_op(c.LT, fp=True) - emit_guard_float_gt = gen_emit_cmp_op(c.GT, fp=True) - emit_guard_float_ge = gen_emit_cmp_op(c.GE, fp=True) - emit_guard_float_eq = gen_emit_cmp_op(c.EQ, fp=True) - emit_guard_float_ne = gen_emit_cmp_op(c.NE, fp=True) + emit_float_le = gen_emit_cmp_op(c.LE, fp=True) + emit_float_lt = gen_emit_cmp_op(c.LT, fp=True) + emit_float_gt = gen_emit_cmp_op(c.GT, fp=True) + emit_float_ge = gen_emit_cmp_op(c.GE, fp=True) + emit_float_eq = gen_emit_cmp_op(c.EQ, fp=True) + emit_float_ne = gen_emit_cmp_op(c.NE, fp=True) def emit_cast_float_to_int(self, op, arglocs, regalloc): l0, temp_loc, res = arglocs @@ -256,9 +246,16 @@ _mixin_ = True - def _emit_guard(self, op, arglocs, fcond, save_exc=False, + def _emit_guard(self, op, arglocs, save_exc=False, is_guard_not_invalidated=False, is_guard_not_forced=False): + if is_guard_not_invalidated: + fcond = c.cond_none + else: + fcond = self.guard_success_cc + self.guard_success_cc = c.cond_none + assert fcond != c.cond_none + fcond = c.negate(fcond) token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], fcond, save_exc, is_guard_not_invalidated, is_guard_not_forced) @@ -279,18 +276,19 @@ return token def emit_guard_true(self, op, arglocs, regalloc): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.cmp_op(0, l0.value, 0, imm=True) - self._emit_guard(op, failargs, c.EQ) - # # ^^^^ If this condition is met, - # # then the guard fails. + self._emit_guard(op, arglocs) def emit_guard_false(self, op, arglocs, regalloc): - l0 = arglocs[0] - failargs = arglocs[1:] - self.mc.cmp_op(0, l0.value, 0, imm=True) - self._emit_guard(op, failargs, c.NE) + self.guard_success_cc = c.negate(self.guard_success_cc) + self._emit_guard(op, arglocs) + + def emit_guard_overflow(self, op, arglocs, regalloc): + self.guard_success_cc = c.SO + self._emit_guard(op, arglocs) + + def emit_guard_no_overflow(self, op, arglocs, regalloc): + self.guard_success_cc = c.NS + self._emit_guard(op, arglocs) def emit_guard_value(self, op, arglocs, regalloc): l0 = arglocs[0] @@ -305,14 +303,16 @@ elif l0.is_fp_reg(): assert l1.is_fp_reg() self.mc.cmp_op(0, l0.value, l1.value, fp=True) - self._emit_guard(op, failargs, c.NE) + self.guard_success_cc = c.EQ + self._emit_guard(op, failargs) emit_guard_nonnull = emit_guard_true emit_guard_isnull = emit_guard_false def emit_guard_class(self, op, arglocs, regalloc): self._cmp_guard_class(op, arglocs, regalloc) - self._emit_guard(op, arglocs[3:], c.NE) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:]) def emit_guard_nonnull_class(self, op, arglocs, regalloc): self.mc.cmp_op(0, arglocs[0].value, 1, imm=True, signed=False) @@ -322,7 +322,8 @@ pmc = OverwritingBuilder(self.mc, patch_pos, 1) pmc.bc(12, 0, self.mc.currpos() - patch_pos) # LT pmc.overwrite() - self._emit_guard(op, arglocs[3:], c.NE, save_exc=False) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs[3:]) def _cmp_guard_class(self, op, locs, regalloc): offset = locs[2] @@ -344,13 +345,24 @@ self.mc.lwz(r.SCRATCH.value, locs[0].value, 4) self.mc.cmp_op(0, r.SCRATCH.value, typeid.value, imm=typeid.is_imm()) - def emit_guard_not_invalidated(self, op, locs, regalloc): - return self._emit_guard(op, locs, c.UH, is_guard_not_invalidated=True) + def emit_guard_not_invalidated(self, op, arglocs, regalloc): + self._emit_guard(op, arglocs, is_guard_not_invalidated=True) + + def emit_guard_not_forced(self, op, arglocs, regalloc): + ofs = self.cpu.get_ofs_of_frame_field('jf_descr') + self.mc.ld(r.SCRATCH.value, r.SPP.value, ofs) + self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs) + class MiscOpAssembler(object): _mixin_ = True + def emit_label(self, op, arglocs, regalloc): + pass + def emit_increment_debug_counter(self, op, arglocs, regalloc): [addr_loc, value_loc] = arglocs self.mc.load(value_loc.value, addr_loc.value, 0) @@ -372,6 +384,7 @@ self.mc.load_imm(r.r5, fail_descr_loc.getint()) self.mc.std(r.r5.value, r.SPP.value, ofs) + ## XXX: gcmap logic here: ## arglist = op.getarglist() ## if arglist and arglist[0].type == REF: ## if self._finish_gcmap: @@ -421,13 +434,18 @@ emit_cast_int_to_ptr = emit_same_as def emit_guard_no_exception(self, op, arglocs, regalloc): - loc = arglocs[0] - failargs = arglocs[1:] - - self.mc.load(loc.value, loc.value, 0) - self.mc.cmp_op(0, loc.value, 0, imm=True) - - self._emit_guard(op, failargs, c.NE, save_exc=True) + self.mc.load_from_addr(r.SCRATCH2, self.cpu.pos_exception()) + self.mc.cmp_op(0, r.SCRATCH2.value, 0, imm=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, arglocs, save_exc=True) + # If the previous operation was a COND_CALL, overwrite its conditional + # jump to jump over this GUARD_NO_EXCEPTION as well, if we can + if self._find_nearby_operation(regalloc,-1).getopnum() == rop.COND_CALL: + jmp_adr, BI, BO = self.previous_cond_call_jcond + relative_target = self.mc.currpos() - jmp_adr + pmc = OverwritingBuilder(self.mc, jmp_adr, 1) + pmc.bc(BO, BI, relative_target) + pmc.overwrite() def emit_guard_exception(self, op, arglocs, regalloc): loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] @@ -435,21 +453,27 @@ self.mc.load_imm(loc1, pos_exception.value) self.mc.load(r.SCRATCH.value, loc1.value, 0) self.mc.cmp_op(0, r.SCRATCH.value, loc.value) - - self._emit_guard(op, failargs, c.NE, save_exc=True) + self.guard_success_cc = c.EQ + self._emit_guard(op, failargs, save_exc=True) self.mc.load_imm(loc, pos_exc_value.value) if resloc: self.mc.load(resloc.value, loc.value, 0) - + self.mc.load_imm(r.SCRATCH, 0) self.mc.store(r.SCRATCH.value, loc.value, 0) self.mc.store(r.SCRATCH.value, loc1.value, 0) - def emit_call(self, op, arglocs, regalloc): + +class CallOpAssembler(object): + + _mixin_ = True + + def _emit_call(self, op, arglocs, is_call_release_gil=False): resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + func_index = 1 + is_call_release_gil + adr = arglocs[func_index] + arglist = arglocs[func_index+1:] cb = callbuilder.CallBuilder(self, adr, arglist, resloc) @@ -458,98 +482,85 @@ cb.argtypes = descr.get_arg_types() cb.restype = descr.get_result_type() - cb.emit() + if is_call_release_gil: + saveerrloc = arglocs[1] + assert saveerrloc.is_imm() + cb.emit_call_release_gil(saveerrloc.value) + else: + cb.emit() - ## def _emit_call(self, adr, arglocs, result=None, result_info=(-1,-1)): - ## n_args = len(arglocs) + def emit_call(self, op, arglocs, regalloc): + self._emit_call(op, arglocs) - ## # collect variables that need to go in registers - ## # and the registers they will be stored in - ## num = 0 - ## fpnum = 0 - ## count = 0 - ## non_float_locs = [] - ## non_float_regs = [] - ## float_locs = [] - ## float_regs = [] - ## stack_args = [] - ## float_stack_arg = False - ## for i in range(n_args): - ## arg = arglocs[i] + def emit_call_may_force(self, op, arglocs, regalloc): + self._store_force_index(self._find_nearby_operation(regalloc, +1)) + self._emit_call(op, arglocs) - ## if arg.type == FLOAT: - ## if fpnum < MAX_FREG_PARAMS: - ## fpreg = r.PARAM_FPREGS[fpnum] - ## float_locs.append(arg) - ## float_regs.append(fpreg) - ## fpnum += 1 - ## # XXX Duplicate float arguments in GPR slots - ## if num < MAX_REG_PARAMS: - ## num += 1 - ## else: - ## stack_args.append(arg) - ## else: - ## stack_args.append(arg) - ## else: - ## if num < MAX_REG_PARAMS: - ## reg = r.PARAM_REGS[num] - ## non_float_locs.append(arg) - ## non_float_regs.append(reg) - ## num += 1 - ## else: - ## stack_args.append(arg) - ## float_stack_arg = True + def emit_call_release_gil(self, op, arglocs, regalloc): + self._store_force_index(self._find_nearby_operation(regalloc, +1)) + self._emit_call(op, arglocs, is_call_release_gil=True) - ## if adr in non_float_regs: - ## non_float_locs.append(adr) - ## non_float_regs.append(r.r11) - ## adr = r.r11 + def _store_force_index(self, guard_op): + assert (guard_op.getopnum() == rop.GUARD_NOT_FORCED or + guard_op.getopnum() == rop.GUARD_NOT_FORCED_2) + faildescr = guard_op.getdescr() + ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') + self.mc.load_imm(r.SCRATCH, rffi.cast(lltype.Signed, + cast_instance_to_gcref(faildescr))) + self.mc.store(r.SCRATCH.value, r.SPP.value, ofs) - ## # compute maximum of parameters passed - ## self.max_stack_params = max(self.max_stack_params, len(stack_args)) + def _find_nearby_operation(self, regalloc, delta): + return regalloc.operations[regalloc.rm.position + delta] - ## # compute offset at which parameters are stored - ## if IS_PPC_32: - ## param_offset = BACKCHAIN_SIZE * WORD - ## else: - ## # space for first 8 parameters - ## param_offset = ((BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) + def emit_cond_call(self, op, arglocs, regalloc): + fcond = self.guard_success_cc + self.guard_success_cc = c.cond_none + assert fcond != c.cond_none + fcond = c.negate(fcond) - ## with scratch_reg(self.mc): - ## if float_stack_arg: - ## self.mc.stfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) - ## for i, arg in enumerate(stack_args): - ## offset = param_offset + i * WORD - ## if arg is not None: - ## if arg.type == FLOAT: - ## self.regalloc_mov(arg, r.f0) - ## self.mc.stfd(r.f0.value, r.SP.value, offset) - ## else: - ## self.regalloc_mov(arg, r.SCRATCH) - ## self.mc.store(r.SCRATCH.value, r.SP.value, offset) - ## if float_stack_arg: - ## self.mc.lfd(r.f0.value, r.SPP.value, FORCE_INDEX_OFS + WORD) + jmp_adr = self.mc.get_relative_pos() + self.mc.trap() # patched later to a 'bc' - ## # remap values stored in core registers - ## remap_frame_layout(self, float_locs, float_regs, r.f0) - ## remap_frame_layout(self, non_float_locs, non_float_regs, r.SCRATCH) + # XXX load_gcmap XXX -> r2 - ## # the actual call - ## if adr.is_imm(): - ## self.mc.call(adr.value) - ## elif adr.is_stack(): - ## self.regalloc_mov(adr, r.SCRATCH) - ## self.mc.call_register(r.SCRATCH) - ## elif adr.is_reg(): - ## self.mc.call_register(adr) - ## else: - ## assert 0, "should not reach here" + # save away r3, r4, r5, r6, r12 into the jitframe + base_ofs = self.cpu.get_baseofs_of_frame_field() + should_be_saved = self._regalloc.rm.reg_bindings.values() + for gpr in [r.r3, r.r4, r.r5, r.r6, r.r12]: + if gpr not in should_be_saved: + continue + v = self.cpu.all_reg_indexes[gpr.value] + self.mc.std(gpr.value, r.SPP.value, v * WORD + base_ofs) + # + # load the 0-to-4 arguments into these registers, with the address of + # the function to call into r12 + remap_frame_layout(self, arglocs, + [r.r12, r.r3, r.r4, r.r5, r.r6][:len(arglocs)], + r.SCRATCH) + # + # figure out which variant of cond_call_slowpath to call, and call it + callee_only = False + floats = False + for reg in regalloc.rm.reg_bindings.values(): + if reg not in regalloc.rm.save_around_call_regs: + break + else: + callee_only = True + if regalloc.fprm.reg_bindings: + floats = True + cond_call_adr = self.cond_call_slowpath[floats * 2 + callee_only] + self.mc.bl_abs(cond_call_adr) + # restoring the registers saved above, and doing pop_gcmap(), is left + # to the cond_call_slowpath helper. We never have any result value. + relative_target = self.mc.currpos() - jmp_adr + pmc = OverwritingBuilder(self.mc, jmp_adr, 1) + BI, BO = c.encoding[fcond] + pmc.bc(BO, BI, relative_target) + pmc.overwrite() + # might be overridden again to skip over the following + # guard_no_exception too + self.previous_cond_call_jcond = jmp_adr, BI, BO - ## self.mark_gc_roots(force_index) - ## # ensure the result is wellformed and stored in the correct location - ## if result is not None and result_info != (-1, -1): - ## self._ensure_result_bit_extension(result, result_info[0], - ## result_info[1]) class FieldOpAssembler(object): @@ -1230,7 +1241,7 @@ self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) self._emit_guard(guard_op, regalloc._prepare_guard(guard_op), - c.LT, save_exc=True) + xxxxxxxxxxxxxxxxx+c.LT, save_exc=True) # ../x86/assembler.py:668 def redirect_call_assembler(self, oldlooptoken, newlooptoken): @@ -1275,7 +1286,8 @@ self.mc.load(r.SCRATCH.value, r.SPP.value, FORCE_INDEX_OFS) self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - self._emit_guard(guard_op, arglocs[1 + numargs:], c.LT, save_exc=True) + self._emit_guard(guard_op, arglocs[1 + numargs:], + xxxxxxxxxxxxxx+c.LT, save_exc=True) def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc): @@ -1307,7 +1319,8 @@ self.mc.load(r.SCRATCH.value, r.SPP.value, 0) self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - self._emit_guard(guard_op, arglocs[1 + numargs:], c.LT, save_exc=True) + self._emit_guard(guard_op, arglocs[1 + numargs:], + xxxxxxxxxxxxxxxxxx+c.LT, save_exc=True) def call_release_gil(self, gcrootmap, save_registers): # XXX don't know whether this is correct @@ -1329,7 +1342,7 @@ class OpAssembler(IntOpAssembler, GuardOpAssembler, MiscOpAssembler, FieldOpAssembler, - StrOpAssembler, + StrOpAssembler, CallOpAssembler, UnicodeOpAssembler, ForceOpAssembler, AllocOpAssembler, FloatOpAssembler): diff --git a/rpython/jit/backend/ppc/ppc_assembler.py b/rpython/jit/backend/ppc/ppc_assembler.py --- a/rpython/jit/backend/ppc/ppc_assembler.py +++ b/rpython/jit/backend/ppc/ppc_assembler.py @@ -32,6 +32,7 @@ from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.rtyper.lltypesystem.lloperation import llop from rpython.jit.backend.ppc.locations import StackLocation, get_fp_offset, imm +from rpython.jit.backend.ppc import callbuilder from rpython.rlib.jit import AsmInfo from rpython.rlib.objectmodel import compute_unique_id from rpython.rlib.rarithmetic import r_uint @@ -71,6 +72,9 @@ def high(w): return (w >> 16) & 0x0000FFFF +class JitFrameTooDeep(Exception): + pass + class AssemblerPPC(OpAssembler, BaseAssembler): #ENCODING_AREA = FORCE_INDEX_OFS @@ -174,18 +178,19 @@ def setup_failure_recovery(self): self.failure_recovery_code = [0, 0, 0, 0] - # TODO: see with we really need the ignored_regs argument def _push_all_regs_to_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: - regs = XXX + regs = PPCRegisterManager.save_around_call_regs else: - regs = r.MANAGED_REGS - # For now, just push all regs to the jitframe + regs = PPCRegisterManager.all_regs + # for reg in regs: - v = r.ALL_REG_INDEXES[reg] - mc.std(reg.value, r.SPP.value, base_ofs + v * WORD) + if reg not in ignored_regs: + v = r.ALL_REG_INDEXES[reg] + mc.std(reg.value, r.SPP.value, base_ofs + v * WORD) + # if withfloats: for reg in r.MANAGED_FP_REGS: v = r.ALL_REG_INDEXES[reg] @@ -195,20 +200,19 @@ callee_only=False): base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: - regs = r.VOLATILES + regs = PPCRegisterManager.save_around_call_regs else: - regs = r.ALL_REGS - for i, reg in enumerate(regs): - # XXX should we progress to higher addressess - mc.load_from_addr(reg, base_ofs - (i * WORD)) - + regs = PPCRegisterManager.all_regs + # + for reg in regs: + if reg not in ignored_regs: + v = r.ALL_REG_INDEXES[reg] + mc.ld(reg.value, r.SPP.value, base_ofs + v * WORD) + # if withfloats: - if callee_only: - regs = r.VOLATILES_FLOAT - else: - regs = r.ALL_FLOAT_REGS - for i, reg in enumerate(regs): - pass # TODO find or create the proper load indexed for fpr's + for reg in r.MANAGED_FP_REGS: + v = r.ALL_REG_INDEXES[reg] + mc.lfd(reg.value, r.SPP.value, base_ofs + v * WORD) def _build_failure_recovery(self, exc, withfloats=False): mc = PPCBuilder() @@ -245,13 +249,114 @@ self.failure_recovery_code[exc + 2 * withfloats] = rawstart self.mc = None - # TODO def build_frame_realloc_slowpath(self): - pass + mc = PPCBuilder() + self.mc = mc - # TODO + # signature of this _frame_realloc_slowpath function: + # * on entry, r0 is the new size + # * on entry, r2 is the gcmap + # * no managed register must be modified + + ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') + mc.store(r.r2.value, r.SPP.value, ofs2) + + self._push_all_regs_to_jitframe(mc, [], self.cpu.supports_floats) + + # Save away the LR inside r30 + mc.mflr(r.RCS1.value) + + # First argument is SPP (= r31), which is the jitframe + mc.mr(r.r3.value, r.SPP.value) + + # Second argument is the new size, which is still in r0 here + mc.mr(r.r4.value, r.r0.value) + + self._store_and_reset_exception(mc, r.RCS2, r.RCS3) + + # Do the call + adr = rffi.cast(lltype.Signed, self.cpu.realloc_frame) + cb = callbuilder.CallBuilder(self, imm(adr), [r.r3, r.r4], r.r3) + cb.emit() + + # The result is stored back into SPP (= r31) + mc.mr(r.SPP.value, r.r3.value) + + self._restore_exception(mc, r.RCS2, r.RCS3) + + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap and gcrootmap.is_shadow_stack: + self._load_shadowstack_top_in_ebx(mc, gcrootmap) + mc.MOV_mr((ebx.value, -WORD), eax.value) + + mc.mtlr(r.RCS1.value) # restore LR + self._pop_all_regs_from_jitframe(mc, [], self.cpu.supports_floats) + mc.blr() + + self._frame_realloc_slowpath = mc.materialize(self.cpu, []) + self.mc = None + + def _store_and_reset_exception(self, mc, excvalloc, exctploc): + """Reset the exception, after fetching it inside the two regs. + """ + mc.load_imm(r.r2, self.cpu.pos_exc_value()) + diff = self.cpu.pos_exception() - self.cpu.pos_exc_value() + assert _check_imm_arg(diff) + # Load the exception fields into the two registers + mc.load(excvalloc.value, r.r2.value, 0) + mc.load(exctploc.value, r.r2.value, diff) + # Zero out the exception fields + mc.li(r.r0.value, 0) + mc.store(r.r0.value, r.r2.value, 0) + mc.store(r.r0.value, r.r2.value, diff) + + def _restore_exception(self, mc, excvalloc, exctploc): + mc.load_imm(r.r2, self.cpu.pos_exc_value()) + diff = self.cpu.pos_exception() - self.cpu.pos_exc_value() + assert _check_imm_arg(diff) + # Store the exception fields from the two registers + mc.store(excvalloc.value, r.r2.value, 0) + mc.store(exctploc.value, r.r2.value, diff) + def _build_cond_call_slowpath(self, supports_floats, callee_only): - pass + """ This builds a general call slowpath, for whatever call happens to + come. + """ + # signature of these cond_call_slowpath functions: + # * on entry, r12 contains the function to call + # * r3, r4, r5, r6 contain arguments for the call + # * r2 is the gcmap + # * the old value of these regs must already be stored in the jitframe + # * on exit, all registers are restored from the jitframe + + mc = PPCBuilder() + self.mc = mc + ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') + mc.store(r.r2.value, r.SPP.value, ofs2) + + # copy registers to the frame, with the exception of r3 to r6 and r12, + # because these have already been saved by the caller. Note that + # this is not symmetrical: these 5 registers are saved by the caller + # but restored here at the end of this function. + self._push_all_regs_to_jitframe(mc, [r.r3, r.r4, r.r5, r.r6, r.r12], + supports_floats, callee_only) + + # Save away the LR inside r30 + mc.mflr(r.RCS1.value) + + # Do the call + cb = callbuilder.CallBuilder(self, r.r12, [r.r3, r.r4, r.r5, r.r6], + None) + cb.emit() + + # Finish + # XXX self._reload_frame_if_necessary(mc, align_stack=True) + + mc.mtlr(r.RCS1.value) # restore LR + self._pop_all_regs_from_jitframe(mc, [], supports_floats, callee_only) + mc.blr() + self.mc = None + return mc.materialize(self.cpu, []) def _build_malloc_slowpath(self): mc = PPCBuilder() @@ -672,15 +777,42 @@ allblocks) self.target_tokens_currently_compiling = {} self.frame_depth_to_patch = [] - #self.max_stack_params = 0 def update_frame_depth(self, frame_depth): + if frame_depth > 0x7fff: + raise JitFrameTooDeep # XXX baseofs = self.cpu.get_baseofs_of_frame_field() self.current_clt.frame_info.update_frame_depth(baseofs, frame_depth) - def patch_stack_checks(self, framedepth, rawstart): - for ofs in self.frame_depth_to_patch: - self._patch_frame_depth(ofs + rawstart, framedepth) + def patch_stack_checks(self, frame_depth): + if frame_depth > 0x7fff: + raise JitFrameTooDeep # XXX + for traps_pos, jmp_target in self.frame_depth_to_patch: + pmc = OverwritingBuilder(self.mc, traps_pos, 3) + # three traps, so exactly three instructions to patch here + pmc.cmpdi(0, r.r2.value, frame_depth) # 1 + pmc.bc(7, 0, jmp_target - (traps_pos + 4)) # 2 "bge+" + pmc.li(r.r0.value, frame_depth) # 3 + pmc.overwrite() + + def _check_frame_depth(self, mc, gcmap): + """ check if the frame is of enough depth to follow this bridge. + Otherwise reallocate the frame in a helper. + """ + descrs = self.cpu.gc_ll_descr.getframedescrs(self.cpu) + ofs = self.cpu.unpack_fielddescr(descrs.arraydescr.lendescr) + mc.ld(r.r2.value, r.SPP.value, ofs) + patch_pos = mc.currpos() + mc.trap() # placeholder for cmpdi(0, r2, ...) + mc.trap() # placeholder for bge + mc.trap() # placeholder for li(r0, ...) + mc.load_imm(r.SCRATCH2, self._frame_realloc_slowpath) + mc.mtctr(r.SCRATCH2.value) + #XXXXX: + if we_are_translated(): XXX #self.load_gcmap(mc, gcmap) # -> r2 + mc.bctrl() + + self.frame_depth_to_patch.append((patch_pos, mc.currpos())) @rgc.no_release_gil def assemble_loop(self, jd_id, unique_id, logger, loopname, inputargs, @@ -717,12 +849,11 @@ self.write_pending_failure_recoveries() full_size = self.mc.get_relative_pos() # + self.patch_stack_checks(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE) rawstart = self.materialize_loop(looptoken) if IS_PPC_64 and IS_BIG_ENDIAN: # fix the function descriptor (3 words) rffi.cast(rffi.LONGP, rawstart)[0] = rawstart + 3 * WORD # - self.patch_stack_checks(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE, - rawstart) looptoken._ppc_loop_code = looppos + rawstart debug_start("jit-backend-addr") debug_print("Loop %d (%s) has address 0x%x to 0x%x (bootstrap 0x%x)" % ( @@ -756,8 +887,10 @@ def _assemble(self, regalloc, inputargs, operations): self._regalloc = regalloc + self.guard_success_cc = c.cond_none regalloc.compute_hint_frame_locations(operations) regalloc.walk_operations(inputargs, operations) + assert self.guard_success_cc == c.cond_none if 1: # we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging frame_depth = regalloc.get_final_frame_depth() @@ -788,16 +921,14 @@ operations, self.current_clt.allgcrefs, self.current_clt.frame_info) - #self._check_frame_depth(self.mc, regalloc.get_gcmap()) - # XXX ^^^^^^^^^^ + self._check_frame_depth(self.mc, "??") frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, operations) codeendpos = self.mc.get_relative_pos() self.write_pending_failure_recoveries() fullsize = self.mc.get_relative_pos() # + self.patch_stack_checks(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE) rawstart = self.materialize_loop(original_loop_token) - self.patch_stack_checks(frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE, - rawstart) debug_bridge(descr_number, rawstart, codeendpos) self.patch_pending_failure_recoveries(rawstart) # patch the jump from original guard @@ -813,15 +944,6 @@ self.teardown() return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos) - def _patch_sp_offset(self, sp_patch_location, rawstart): - mc = PPCBuilder() - frame_depth = self.compute_frame_depth(self.current_clt.frame_depth, - self.current_clt.param_depth) - frame_depth -= self.OFFSET_SPP_TO_OLD_BACKCHAIN - mc.load_imm(r.SCRATCH, -frame_depth) - mc.add(r.SP.value, r.SPP.value, r.SCRATCH.value) - mc.copy_to_raw_memory(rawstart + sp_patch_location) - DESCR_REF = 0x00 DESCR_INT = 0x01 DESCR_FLOAT = 0x02 @@ -938,6 +1060,10 @@ ptr = rffi.cast(lltype.Signed, gcmap) mc.load_imm(r.r2, ptr) + def push_gcmap(self, mc, gcmap, store): + assert store is True + # XXX IGNORED FOR NOW + def break_long_loop(self): # If the loop is too long, the guards in it will jump forward # more than 32 KB. We use an approximate hack to know if we @@ -962,6 +1088,9 @@ self.mc.mtctr(r.r0.value) self.mc.load_imm(r.r0, fail_descr) self.mc.bctr() + # we need to write at least 6 insns here, for patch_jump_for_descr() + while self.mc.currpos() < startpos + 6 * 4: + self.mc.trap() return startpos def write_pending_failure_recoveries(self): @@ -1004,7 +1133,7 @@ # conditional jump. We must patch this conditional jump to go # to 'adr_new_target'. If the target is too far away, we can't # patch it inplace, and instead we patch the quick failure code - # (which should be at least 5 instructions, so enough). + # (which should be at least 6 instructions, so enough). # --- XXX for now we always use the second solution --- mc = PPCBuilder() mc.b_abs(adr_new_target) @@ -1098,63 +1227,44 @@ assert 0, "not supported location" mov_loc_loc = regalloc_mov - def regalloc_push(self, loc): + def regalloc_push(self, loc, already_pushed): """Pushes the value stored in loc to the stack Can trash the current value of SCRATCH when pushing a stack loc""" - self.mc.addi(r.SP.value, r.SP.value, -WORD) # decrease stack pointer assert IS_PPC_64, 'needs to updated for ppc 32' - if loc.is_imm(): - with scratch_reg(self.mc): + index = WORD * (~already_pushed) + + if loc.type == FLOAT: + if not loc.is_fp_reg(): + self.regalloc_mov(loc, r.FP_SCRATCH) + loc = r.FP_SCRATCH + self.mc.stfd(loc.value, r.SP.value, index) + else: + if not loc.is_core_reg(): self.regalloc_mov(loc, r.SCRATCH) - self.mc.store(r.SCRATCH.value, r.SP.value, 0) - elif loc.is_imm_float(): - with scratch_reg(self.mc): - self.regalloc_mov(loc, r.FP_SCRATCH) - self.mc.store(r.FP_SCRATCH.value, r.SP.value, 0) - elif loc.is_stack(): - # XXX this code has to be verified - with scratch_reg(self.mc): - self.regalloc_mov(loc, r.SCRATCH) - # push value - self.mc.store(r.SCRATCH.value, r.SP.value, 0) - elif loc.is_reg(): - # push value - self.mc.store(loc.value, r.SP.value, 0) - elif loc.is_fp_reg(): - self.mc.addi(r.SP.value, r.SP.value, -WORD) # decrease stack pointer - # push value - self.mc.stfd(loc.value, r.SP.value, 0) - else: - raise AssertionError('Trying to push an invalid location') + loc = r.SCRATCH + self.mc.std(loc.value, r.SP.value, index) - def regalloc_pop(self, loc): + def regalloc_pop(self, loc, already_pushed): """Pops the value on top of the stack to loc. Can trash the current value of SCRATCH when popping to a stack loc""" assert IS_PPC_64, 'needs to updated for ppc 32' - if loc.is_stack(): - # XXX this code has to be verified - with scratch_reg(self.mc): - # pop value - if IS_PPC_32: - self.mc.lwz(r.SCRATCH.value, r.SP.value, 0) - else: - self.mc.ld(r.SCRATCH.value, r.SP.value, 0) - self.mc.addi(r.SP.value, r.SP.value, WORD) # increase stack pointer - self.regalloc_mov(r.SCRATCH, loc) - elif loc.is_reg(): - # pop value - if IS_PPC_32: - self.mc.lwz(loc.value, r.SP.value, 0) + + index = WORD * (~already_pushed) + + if loc.type == FLOAT: + if loc.is_fp_reg(): + self.mc.lfd(loc.value, r.SP.value, index) else: - self.mc.ld(loc.value, r.SP.value, 0) - self.mc.addi(r.SP.value, r.SP.value, WORD) # increase stack pointer - elif loc.is_fp_reg(): - self.mc.lfd(loc.value, r.SP.value, 0) - self.mc.addi(r.SP.value, r.SP.value, WORD) # increase stack pointer + self.mc.lfd(r.FP_SCRATCH.value, r.SP.value, index) + self.regalloc_mov(r.FP_SCRATCH.value, loc) else: - raise AssertionError('Trying to pop to an invalid location') + if loc.is_core_reg(): + self.mc.ld(loc.value, r.SP.value, index) + else: + self.mc.ld(r.SCRATCH.value, r.SP.value, index) + self.regalloc_mov(r.SCRATCH.value, loc) def malloc_cond(self, nursery_free_adr, nursery_top_adr, size): assert size & (WORD-1) == 0 # must be correctly aligned @@ -1245,17 +1355,7 @@ print "[PPC/asm] %s not implemented" % op.getopname() raise NotImplementedError(op) -def notimplemented_op_with_guard(self, op, guard_op, arglocs, regalloc): - print "[PPC/asm] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - -def add_none_argument(fn): - return (lambda self, op, arglocs, regalloc: - fn(self, op, None, arglocs, regalloc)) - operations = [notimplemented_op] * (rop._LAST + 1) -operations_with_guard = [notimplemented_op_with_guard] * (rop._LAST + 1) for key, value in rop.__dict__.items(): key = key.lower() @@ -1266,16 +1366,5 @@ func = getattr(AssemblerPPC, methname).im_func operations[value] = func -for key, value in rop.__dict__.items(): - key = key.lower() - if key.startswith('_'): - continue - methname = 'emit_guard_%s' % key - if hasattr(AssemblerPPC, methname): - assert operations[value] is notimplemented_op - func = getattr(AssemblerPPC, methname).im_func - operations_with_guard[value] = func - operations[value] = add_none_argument(func) - class BridgeAlreadyCompiled(Exception): pass diff --git a/rpython/jit/backend/ppc/ppc_field.py b/rpython/jit/backend/ppc/ppc_field.py --- a/rpython/jit/backend/ppc/ppc_field.py +++ b/rpython/jit/backend/ppc/ppc_field.py @@ -49,7 +49,8 @@ "XO4": (30, 31), "XO5": (27, 29), "XO6": (21, 29), - "XO7": (27, 30) + "XO7": (27, 30), + "LL": ( 9, 10), } diff --git a/rpython/jit/backend/ppc/regalloc.py b/rpython/jit/backend/ppc/regalloc.py --- a/rpython/jit/backend/ppc/regalloc.py +++ b/rpython/jit/backend/ppc/regalloc.py @@ -20,6 +20,7 @@ from rpython.jit.backend.llsupport import symbolic from rpython.jit.backend.llsupport.descr import ArrayDescr import rpython.jit.backend.ppc.register as r +import rpython.jit.backend.ppc.condition as c from rpython.jit.backend.llsupport.descr import unpack_arraydescr from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr @@ -55,7 +56,7 @@ class FPRegisterManager(RegisterManager): all_regs = r.MANAGED_FP_REGS box_types = [FLOAT] - save_around_call_regs = r.VOLATILES_FLOAT + save_around_call_regs = [_r for _r in all_regs if _r in r.VOLATILES_FLOAT] def convert_to_imm(self, c): assert isinstance(c, ConstFloat) @@ -92,7 +93,8 @@ all_regs = r.MANAGED_REGS box_types = None # or a list of acceptable types no_lower_byte_regs = all_regs - save_around_call_regs = r.VOLATILES + save_around_call_regs = [_r for _r in all_regs if _r in r.VOLATILES] + frame_reg = r.SPP REGLOC_TO_COPY_AREA_OFS = { r.r5: MY_COPY_OF_REGS + 0 * WORD, @@ -281,13 +283,25 @@ forbidden_vars = self.rm.temp_boxes return self.rm.force_allocate_reg(var, forbidden_vars) + def force_allocate_reg_or_cc(self, var): + assert var.type == INT + if self.next_op_can_accept_cc(self.operations, self.rm.position): + # hack: return the SPP location to mean "lives in CC". This + # SPP will not actually be used, and the location will be freed + # after the next op as usual. + self.rm.force_allocate_frame_reg(var) + return r.SPP + else: + # else, return a regular register (not SPP). + return self.force_allocate_reg(var) + def walk_operations(self, inputargs, operations): from rpython.jit.backend.ppc.ppc_assembler import ( - operations_with_guard as asm_operations_with_guard, operations as asm_operations) i = 0 self.limit_loop_break = (self.assembler.mc.get_relative_pos() + LIMIT_LOOP_BREAK) + self.operations = operations while i < len(operations): op = operations[i] self.assembler.mc.mark_op(op) @@ -306,21 +320,11 @@ self.fprm.temp_boxes.append(box) # opnum = op.getopnum() - if self.can_merge_with_next_guard(op, i, operations): - i += 1 - self.rm.position = i - self.fprm.position = i - arglocs = oplist_with_guard[opnum](self, op, operations[i]) - assert arglocs is not None - asm_operations_with_guard[opnum](self.assembler, op, - operations[i], - arglocs, self) - elif not we_are_translated() and opnum == -124: + if not we_are_translated() and opnum == -124: self._consider_force_spill(op) else: arglocs = oplist[opnum](self, op) - if arglocs is not None: - asm_operations[opnum](self.assembler, op, arglocs, self) + asm_operations[opnum](self.assembler, op, arglocs, self) self.free_op_vars() self.possibly_free_var(op.result) self.rm._check_invariants() @@ -334,6 +338,7 @@ assert not self.fprm.reg_bindings self.flush_loop() self.assembler.mc.mark_op(None) # end of the loop + self.operations = None for arg in inputargs: self.possibly_free_var(arg) @@ -344,6 +349,10 @@ while self.min_bytes_before_label > mc.get_relative_pos(): mc.nop() + def get_gcmap(self, noregs=False): + #xxxxxx + return '???' + def loc(self, var): if var.type == FLOAT: return self.fprm.loc(var) @@ -436,46 +445,46 @@ prepare_uint_rshift = helper.prepare_binary_op prepare_uint_floordiv = helper.prepare_binary_op - prepare_guard_int_add_ovf = helper.prepare_int_binary_ovf - prepare_guard_int_sub_ovf = helper.prepare_int_binary_ovf - prepare_guard_int_mul_ovf = helper.prepare_int_binary_ovf + prepare_int_add_ovf = helper.prepare_binary_op + prepare_int_sub_ovf = helper.prepare_binary_op + prepare_int_mul_ovf = helper.prepare_binary_op prepare_int_neg = helper.prepare_unary_op prepare_int_invert = helper.prepare_unary_op prepare_int_signext = helper.prepare_unary_op - prepare_guard_int_le = helper.prepare_cmp_op - prepare_guard_int_lt = helper.prepare_cmp_op - prepare_guard_int_ge = helper.prepare_cmp_op - prepare_guard_int_gt = helper.prepare_cmp_op - prepare_guard_int_eq = helper.prepare_cmp_op - prepare_guard_int_ne = helper.prepare_cmp_op + prepare_int_le = helper.prepare_cmp_op + prepare_int_lt = helper.prepare_cmp_op + prepare_int_ge = helper.prepare_cmp_op + prepare_int_gt = helper.prepare_cmp_op + prepare_int_eq = helper.prepare_cmp_op + prepare_int_ne = helper.prepare_cmp_op - prepare_guard_ptr_eq = prepare_guard_int_eq - prepare_guard_ptr_ne = prepare_guard_int_ne + prepare_ptr_eq = prepare_int_eq + prepare_ptr_ne = prepare_int_ne - prepare_guard_instance_ptr_eq = prepare_guard_ptr_eq - prepare_guard_instance_ptr_ne = prepare_guard_ptr_ne + prepare_instance_ptr_eq = prepare_ptr_eq + prepare_instance_ptr_ne = prepare_ptr_ne - prepare_guard_uint_lt = helper.prepare_cmp_op_unsigned - prepare_guard_uint_le = helper.prepare_cmp_op_unsigned - prepare_guard_uint_gt = helper.prepare_cmp_op_unsigned - prepare_guard_uint_ge = helper.prepare_cmp_op_unsigned + prepare_uint_lt = helper.prepare_cmp_op_unsigned + prepare_uint_le = helper.prepare_cmp_op_unsigned + prepare_uint_gt = helper.prepare_cmp_op_unsigned + prepare_uint_ge = helper.prepare_cmp_op_unsigned - prepare_guard_int_is_true = helper.prepare_unary_cmp - prepare_guard_int_is_zero = helper.prepare_unary_cmp + prepare_int_is_true = helper.prepare_unary_cmp + prepare_int_is_zero = helper.prepare_unary_cmp prepare_float_add = helper.prepare_binary_op prepare_float_sub = helper.prepare_binary_op prepare_float_mul = helper.prepare_binary_op prepare_float_truediv = helper.prepare_binary_op - prepare_guard_float_lt = helper.prepare_float_cmp - prepare_guard_float_le = helper.prepare_float_cmp - prepare_guard_float_eq = helper.prepare_float_cmp - prepare_guard_float_ne = helper.prepare_float_cmp - prepare_guard_float_gt = helper.prepare_float_cmp - prepare_guard_float_ge = helper.prepare_float_cmp + prepare_float_lt = helper.prepare_float_cmp + prepare_float_le = helper.prepare_float_cmp + prepare_float_eq = helper.prepare_float_cmp + prepare_float_ne = helper.prepare_float_cmp + prepare_float_gt = helper.prepare_float_cmp + prepare_float_ge = helper.prepare_float_cmp prepare_float_neg = helper.prepare_unary_op prepare_float_abs = helper.prepare_unary_op @@ -541,14 +550,21 @@ # return args - def prepare_guard_true(self, op): - l0 = self.ensure_reg(op.getarg(0)) - args = self._prepare_guard(op, [l0]) - return args + def load_condition_into_cc(self, box): + if self.assembler.guard_success_cc == c.cond_none: + loc = self.ensure_reg(box) + mc = self.assembler.mc + mc.cmp_op(0, loc.value, 0, imm=True) + self.assembler.guard_success_cc = c.NE - prepare_guard_false = prepare_guard_true - prepare_guard_nonnull = prepare_guard_true - prepare_guard_isnull = prepare_guard_true + def _prepare_guard_cc(self, op): + self.load_condition_into_cc(op.getarg(0)) + return self._prepare_guard(op) + + prepare_guard_true = _prepare_guard_cc + prepare_guard_false = _prepare_guard_cc + prepare_guard_nonnull = _prepare_guard_cc + prepare_guard_isnull = _prepare_guard_cc def prepare_guard_not_invalidated(self, op): pos = self.assembler.mc.get_relative_pos() @@ -570,10 +586,13 @@ return arglocs def prepare_guard_no_exception(self, op): - loc = self.ensure_reg(ConstInt(self.cpu.pos_exception())) - arglocs = self._prepare_guard(op, [loc]) + arglocs = self._prepare_guard(op) return arglocs + prepare_guard_no_overflow = prepare_guard_no_exception + prepare_guard_overflow = prepare_guard_no_exception + prepare_guard_not_forced = prepare_guard_no_exception + def prepare_guard_value(self, op): l0 = self.ensure_reg(op.getarg(0)) l1 = self.ensure_reg_or_16bit_imm(op.getarg(1)) @@ -863,12 +882,13 @@ if effectinfo is not None: oopspecindex = effectinfo.oopspecindex if oopspecindex == EffectInfo.OS_MATH_SQRT: + xxxxxxxxx args = self.prepare_math_sqrt(op) self.assembler.emit_math_sqrt(op, args, self) return return self._prepare_call(op) - def _prepare_call(self, op, force_store=[], save_all_regs=False): + def _prepare_call(self, op, save_all_regs=False): args = [] args.append(None) for i in range(op.numargs()): @@ -1003,12 +1023,11 @@ if jump_op is not None and jump_op.getdescr() is descr: self._compute_hint_frame_locations_from_descr(descr) - def prepare_guard_call_may_force(self, op, guard_op): - args = self._prepare_call(op, save_all_regs=True) - return self._prepare_guard(guard_op, args) + def prepare_call_may_force(self, op): + return self._prepare_call(op, save_all_regs=True) - prepare_guard_call_release_gil = prepare_guard_call_may_force - + prepare_call_release_gil = prepare_call_may_force + def prepare_guard_call_assembler(self, op, guard_op): descr = op.getdescr() assert isinstance(descr, JitCellToken) @@ -1055,19 +1074,21 @@ ofs_loc = self.ensure_reg_or_16bit_imm(ConstInt(ofs)) return [base_loc, startindex_loc, length_loc, ofs_loc, imm(itemsize)] -def add_none_argument(fn): - return lambda self, op: fn(self, op, None) + def prepare_cond_call(self, op): + self.load_condition_into_cc(op.getarg(0)) + locs = [] + # support between 0 and 4 integer arguments + assert 2 <= op.numargs() <= 2 + 4 + for i in range(1, op.numargs()): + loc = self.loc(op.getarg(i)) + assert loc.type != FLOAT + locs.append(loc) + return locs def notimplemented(self, op): print "[PPC/regalloc] %s not implemented" % op.getopname() raise NotImplementedError(op) -def notimplemented_with_guard(self, op, guard_op): - print "[PPC/regalloc] %s with guard %s not implemented" % \ - (op.getopname(), guard_op.getopname()) - raise NotImplementedError(op) - - def force_int(intvalue): # a hack before transaction: force the intvalue argument through # rffi.cast(), to turn Symbolics into real values @@ -1075,7 +1096,6 @@ oplist = [notimplemented] * (rop._LAST + 1) -oplist_with_guard = [notimplemented_with_guard] * (rop._LAST + 1) for key, value in rop.__dict__.items(): key = key.lower() @@ -1085,14 +1105,3 @@ if hasattr(Regalloc, methname): func = getattr(Regalloc, methname).im_func oplist[value] = func - -for key, value in rop.__dict__.items(): - key = key.lower() - if key.startswith('_'): - continue - methname = 'prepare_guard_%s' % key - if hasattr(Regalloc, methname): - assert oplist[value] is notimplemented - func = getattr(Regalloc, methname).im_func - oplist_with_guard[value] = func - oplist[value] = add_none_argument(func) diff --git a/rpython/jit/backend/ppc/register.py b/rpython/jit/backend/ppc/register.py --- a/rpython/jit/backend/ppc/register.py +++ b/rpython/jit/backend/ppc/register.py @@ -26,10 +26,13 @@ SCRATCH = r0 SCRATCH2 = r2 FP_SCRATCH = f0 -SP = r1 -TOC = r2 -RES = r3 -SPP = r31 +SP = r1 # stack pointer register +TOC = r2 # the TOC, but unused inside the code we generated +RES = r3 # the result of calls +SPP = r31 # the frame pointer +RCS1 = r30 # a random managed non-volatile register +RCS2 = r29 # a random managed non-volatile register +RCS3 = r28 # a random managed non-volatile register MANAGED_REGS = [r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r25, r26, r27, r28, r29, r30] @@ -38,6 +41,10 @@ MANAGED_FP_REGS = VOLATILES_FLOAT[1:] #+ NONVOLATILES_FLOAT +assert RCS1 in MANAGED_REGS and RCS1 in NONVOLATILES +assert RCS2 in MANAGED_REGS and RCS2 in NONVOLATILES +assert RCS3 in MANAGED_REGS and RCS3 in NONVOLATILES + # The JITFRAME_FIXED_SIZE is measured in words, and should be the # number of registers that need to be saved into the jitframe when diff --git a/rpython/jit/backend/ppc/runner.py b/rpython/jit/backend/ppc/runner.py --- a/rpython/jit/backend/ppc/runner.py +++ b/rpython/jit/backend/ppc/runner.py @@ -1,6 +1,7 @@ import py from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.llinterp import LLInterpreter +from rpython.rlib import rgc #from rpython.jit.backend.ppc.arch import FORCE_INDEX_OFS from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU from rpython.jit.backend.ppc.ppc_assembler import AssemblerPPC @@ -14,9 +15,10 @@ class PPC_CPU(AbstractLLCPU): + supports_floats = True + # missing: supports_singlefloats IS_64_BIT = True - BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed) from rpython.jit.backend.ppc.register import JITFRAME_FIXED_SIZE frame_reg = r.SP @@ -24,7 +26,10 @@ for _i, _r in enumerate(r.MANAGED_REGS): all_reg_indexes[_r.value] = _i gen_regs = r.MANAGED_REGS - float_regs = r.MANAGED_FP_REGS + float_regs = [None] + r.MANAGED_FP_REGS + # ^^^^ we leave a never-used hole for f0 in the jitframe + # for rebuild_faillocs_from_descr(), as a counter-workaround + # for the reverse hack in ALL_REG_INDEXES def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): @@ -36,15 +41,14 @@ AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) - # floats are supported. singlefloats are not supported yet - self.supports_floats = True - def setup(self): self.assembler = AssemblerPPC(self) + @rgc.no_release_gil def setup_once(self): self.assembler.setup_once() + @rgc.no_release_gil def finish_once(self): self.assembler.finish_once() @@ -55,69 +59,12 @@ return self.assembler.assemble_bridge(faildescr, inputargs, operations, original_loop_token, log, logger) - @staticmethod def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return PPC_CPU.cast_adr_to_int(adr) + cast_ptr_to_int._annspecialcase_ = 'specialize:arglltype(0)' + cast_ptr_to_int = staticmethod(cast_ptr_to_int) - # XXX find out how big FP registers are on PPC32 - all_null_registers = lltype.malloc(rffi.LONGP.TO, - len(r.MANAGED_REGS), - flavor='raw', zero=True, immortal=True) - - def force(self, addr_of_force_index): - TP = rffi.CArrayPtr(lltype.Signed) - - spilling_pointer = addr_of_force_index - FORCE_INDEX_OFS - - fail_index = rffi.cast(TP, addr_of_force_index)[0] - assert fail_index >= 0, "already forced!" - faildescr = self.get_fail_descr_from_number(fail_index) - rffi.cast(TP, addr_of_force_index)[0] = ~fail_index - - bytecode = self.assembler._find_failure_recovery_bytecode(faildescr) - addr_all_null_registers = rffi.cast(rffi.LONG, self.all_null_registers) - # start of "no gc operation!" block - fail_index_2 = self.assembler.failure_recovery_func( - bytecode, - spilling_pointer, - addr_all_null_registers) - self.assembler.leave_jitted_hook() - # end of "no gc operation!" block - assert fail_index == fail_index_2 - return faildescr - - # return the number of values that can be returned - def get_latest_value_count(self): - return self.assembler.fail_boxes_count - - # fetch the result of the computation and return it - def get_latest_value_float(self, index): - return self.assembler.fail_boxes_float.getitem(index) - - def get_latest_value_int(self, index): - return self.assembler.fail_boxes_int.getitem(index) - - def get_latest_value_ref(self, index): - return self.assembler.fail_boxes_ptr.getitem(index) - - def get_latest_force_token(self): - return self.assembler.fail_force_index - - def get_on_leave_jitted_hook(self): - return self.assembler.leave_jitted_hook - - # walk through the given trace and generate machine code - def _walk_trace_ops(self, codebuilder, operations): - for op in operations: - codebuilder.build_op(op, self) - - def get_box_index(self, box): - return self.arg_to_box[box] - - def teardown(self): - self.patch_list = None - self.reg_map = None def redirect_call_assembler(self, oldlooptoken, newlooptoken): self.assembler.redirect_call_assembler(oldlooptoken, newlooptoken) diff --git a/rpython/jit/backend/ppc/test/test_runner.py b/rpython/jit/backend/ppc/test/test_runner.py --- a/rpython/jit/backend/ppc/test/test_runner.py +++ b/rpython/jit/backend/ppc/test/test_runner.py @@ -3,7 +3,7 @@ from rpython.jit.tool.oparser import parse from rpython.jit.metainterp.history import (AbstractFailDescr, AbstractDescr, - BasicFailDescr, + BasicFailDescr, BasicFinalDescr, BoxInt, Box, BoxPtr, From noreply at buildbot.pypy.org Fri Sep 11 15:22:41 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 11 Sep 2015 15:22:41 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: hg merge decda77d1ea6 (branch optimize-cond-call) Message-ID: <20150911132241.781F41C12F8@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79591:c9c35ead1602 Date: 2015-09-11 15:16 +0200 http://bitbucket.org/pypy/pypy/changeset/c9c35ead1602/ Log: hg merge decda77d1ea6 (branch optimize-cond-call) diff too long, truncating to 2000 out of 3637 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -352,8 +353,7 @@ Except when otherwise stated (look for LICENSE files or copyright/license information at the beginning of each file) the files in the 'lib-python/2.7' directory are all copyrighted by the Python Software Foundation and licensed -under the Python Software License of which you can find a copy here: -http://www.python.org/doc/Copyright.html +under the terms that you can find here: https://docs.python.org/2/license.html License for 'pypy/module/unicodedata/' ====================================== @@ -430,9 +430,9 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at - https://code.google.com/p/gperftools/source/browse/COPYING + https://github.com/gperftools/gperftools/blob/master/COPYING diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.2.0 +Version: 1.3.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.2.0" -__version_info__ = (1, 2, 0) +__version__ = "1.3.0" +__version_info__ = (1, 3, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -46,7 +46,7 @@ # endif #else # include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include # endif #endif @@ -214,6 +214,12 @@ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -15,9 +15,11 @@ except ImportError: lock = None -_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", - re.MULTILINE) +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") @@ -39,6 +41,7 @@ macros = {} for match in _r_define.finditer(csource): macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) # Replace "[...]" with "[__dotdotdotarray__]" @@ -423,13 +426,10 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - elif (len(params) == 1 and - isinstance(params[0].type, pycparser.c_ast.TypeDecl) and - isinstance(params[0].type.type, pycparser.c_ast.IdentifierType) - and list(params[0].type.type.names) == ['void']): - del params[0] args = [self._as_func_arg(self._get_type(argdeclnode.type)) for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] result = self._get_type(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) @@ -648,10 +648,21 @@ assert typenames[-1] == '__dotdotdot__' if len(typenames) == 1: return model.unknown_type(decl.name) - for t in typenames[:-1]: - if t not in ['int', 'short', 'long', 'signed', 'unsigned', 'char']: - raise api.FFIError(':%d: bad usage of "..."' % decl.coord.line) + + if (typenames[:-1] == ['float'] or + typenames[:-1] == ['double']): + # not for 'long double' so far + result = model.UnknownFloatType(decl.name) + else: + for t in typenames[:-1]: + if t not in ['int', 'short', 'long', 'signed', + 'unsigned', 'char']: + raise api.FFIError(':%d: bad usage of "..."' % + decl.coord.line) + result = model.UnknownIntegerType(decl.name) + if self._uses_new_feature is None: self._uses_new_feature = "'typedef %s... %s'" % ( ' '.join(typenames[:-1]), decl.name) - return model.UnknownIntegerType(decl.name) + + return result diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -158,12 +158,23 @@ self.c_name_with_marker = name + '&' def is_integer_type(self): - return True # for now + return True def build_backend_type(self, ffi, finishlist): raise NotImplementedError("integer type '%s' can only be used after " "compilation" % self.name) +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + class BaseFunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -79,7 +79,9 @@ #define _CFFI_PRIM_UINTMAX 47 #define _CFFI__NUM_PRIM 48 -#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) struct _cffi_global_s { diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -4,11 +4,6 @@ VERSION = "0x2601" -try: - int_type = (int, long) -except NameError: # Python 3 - int_type = int - class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): @@ -473,6 +468,10 @@ if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), tp.name.replace(' ', '_')) @@ -527,6 +526,8 @@ if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type(): return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double': return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: @@ -1112,6 +1113,12 @@ ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -81,10 +81,16 @@ allsources.extend(kwds.pop('sources', [])) ext = Extension(name=module_name, sources=allsources, **kwds) - def make_mod(tmpdir): + def make_mod(tmpdir, pre_run=None): c_file = os.path.join(tmpdir, module_name + source_extension) log.info("generating cffi module %r" % c_file) mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) updated = recompiler.make_c_source(ffi, module_name, source, c_file) if not updated: log.info("already up-to-date") @@ -98,7 +104,8 @@ class build_ext_make_mod(base_class): def run(self): if ext.sources[0] == '$PLACEHOLDER': - ext.sources[0] = make_mod(self.build_temp) + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) base_class.run(self) dist.cmdclass['build_ext'] = build_ext_make_mod # NB. multiple runs here will create multiple 'build_ext_make_mod' diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -28,7 +28,7 @@ def _where_is_errno(): return standard_c_lib.__errno_location() -elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'): +elif sys.platform == 'darwin' or sys.platform.startswith('freebsd'): standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int) standard_c_lib.__error.argtypes = None def _where_is_errno(): diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -31,15 +31,14 @@ and add the new file to pypy/doc/index-of-whatsnew.rst * go to pypy/tool/release and run ``force-builds.py `` - The following binaries should be built, however, we need more buildbots - - JIT: windows, linux, os/x, armhf, armel - - no JIT: windows, linux, os/x - - sandbox: linux, os/x + The following JIT binaries should be built, however, we need more buildbots + windows, linux-32, linux-64, osx64, armhf-raring, armhf-raspberrian, armel, + freebsd64 * wait for builds to complete, make sure there are no failures * download the builds, repackage binaries. Tag the release version and download and repackage source from bitbucket. You may find it - convenient to use the ``repackage.sh`` script in pypy/tools to do this. + convenient to use the ``repackage.sh`` script in pypy/tool/release to do this. Otherwise repackage and upload source "-src.tar.bz2" to bitbucket and to cobra, as some packagers prefer a clearly labeled source package diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 diff --git a/pypy/doc/whatsnew-2.6.1.rst b/pypy/doc/whatsnew-2.6.1.rst --- a/pypy/doc/whatsnew-2.6.1.rst +++ b/pypy/doc/whatsnew-2.6.1.rst @@ -32,7 +32,10 @@ ``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) .. branch: cffi-callback-onerror +Part of cffi 1.2. + .. branch: cffi-new-allocator +Part of cffi 1.2. .. branch: unicode-dtype @@ -67,3 +70,7 @@ .. branch: vmprof-review Clean up of vmprof, notably to handle correctly multiple threads + +.. branch: no_boehm_dl + +Remove extra link library from Boehm 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 @@ -3,5 +3,5 @@ ======================= .. this is a revision shortly after release-2.6.1 -.. startrev: 83ebc73d4fcb +.. startrev: 07769be4057b diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.2.0" +VERSION = "1.3.0" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py --- a/pypy/module/_cffi_backend/cffi_opcode.py +++ b/pypy/module/_cffi_backend/cffi_opcode.py @@ -9,16 +9,16 @@ assert isinstance(self.arg, str) return '(_cffi_opcode_t)(%s)' % (self.arg,) classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg) + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) def as_python_bytes(self): - if self.op is None: - if self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): from .ffiplatform import VerificationError raise VerificationError("cannot emit to Python: %r" % (self.arg,)) return format_four_bytes((self.arg << 8) | self.op) @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -81,6 +81,13 @@ if num == cffi_opcode._UNKNOWN_PRIM: raise oefmt(ffi.w_FFIError, "primitive integer type with an " "unexpected size (or not an integer type at all)") + elif num == cffi_opcode._UNKNOWN_FLOAT_PRIM: + raise oefmt(ffi.w_FFIError, "primitive floating-point type with an " + "unexpected size (or not a float type at all)") + elif num == cffi_opcode._UNKNOWN_LONG_DOUBLE: + raise oefmt(ffi.w_FFIError, "primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") else: raise oefmt(space.w_NotImplementedError, "prim=%d", num) realize_cache = space.fromcache(RealizeCache) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,6 +1,9 @@ # ____________________________________________________________ import sys +assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" + " of cffi that differs from the one that we" + " get from 'import _cffi_backend'") if sys.version_info < (3,): type_or_class = "type" mandatory_b_prefix = '' @@ -3424,7 +3427,3 @@ "be 'foo *', but the types are different (check " "that you are not e.g. mixing up different ffi " "instances)") - -def test_version(): - # this test is here mostly for PyPy - assert __version__ == "1.2.0" diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -1,8 +1,12 @@ +import sys + class AppTestMemory: spaceconfig = dict(usemodules=('_multiprocessing', 'mmap', '_rawffi', 'itertools', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii')) + if sys.platform != 'win32': + spaceconfig['usemodules'] += ('fcntl',) def test_address_of(self): import _multiprocessing diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py b/pypy/module/_multiprocessing/test/test_semaphore.py --- a/pypy/module/_multiprocessing/test/test_semaphore.py +++ b/pypy/module/_multiprocessing/test/test_semaphore.py @@ -1,12 +1,19 @@ +import sys + from pypy.module._multiprocessing.interp_semaphore import ( RECURSIVE_MUTEX, SEMAPHORE) class AppTestSemaphore: spaceconfig = dict(usemodules=('_multiprocessing', 'thread', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii', 'struct')) + if sys.platform == 'win32': + spaceconfig['usemodules'] += ('_rawffi',) + else: + spaceconfig['usemodules'] += ('fcntl',) + def setup_class(cls): cls.w_SEMAPHORE = cls.space.wrap(SEMAPHORE) cls.w_RECURSIVE = cls.space.wrap(RECURSIVE_MUTEX) diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -379,6 +379,8 @@ PyObject *ht_name, *ht_slots; } PyHeapTypeObject; +#define PyObject_Bytes PyObject_Str + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py @@ -160,6 +160,35 @@ assert func.name == 'sin' assert func.BType == ', ), , False>' +def test_remove_line_continuation_comments(): + ffi = FFI(backend=FakeBackend()) + ffi.cdef(""" + double // blah \\ + more comments + x(void); + double // blah\\\\ + y(void); + double // blah\\ \ + etc + z(void); + """) + m = ffi.dlopen(lib_m) + m.x + m.y + m.z + +def test_line_continuation_in_defines(): + ffi = FFI(backend=FakeBackend()) + ffi.cdef(""" + #define ABC\\ + 42 + #define BCD \\ + 43 + """) + m = ffi.dlopen(lib_m) + assert m.ABC == 42 + assert m.BCD == 43 + def test_define_not_supported_for_now(): ffi = FFI(backend=FakeBackend()) e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"') @@ -238,6 +267,13 @@ ffi = FFI() ffi.cdef("typedef _Bool bool; void f(bool);") +def test_void_renamed_as_only_arg(): + ffi = FFI() + ffi.cdef("typedef void void_t1;" + "typedef void_t1 void_t;" + "typedef int (*func_t)(void_t);") + assert ffi.typeof("func_t").args == () + def test_win_common_types(): from cffi.commontypes import COMMON_TYPES, _CACHE from cffi.commontypes import win_common_types, resolve_common_type diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1,7 +1,7 @@ # Generated by pypy/tool/import_cffi.py import sys, os, py -from cffi import FFI, VerificationError +from cffi import FFI, VerificationError, FFIError from cffi import recompiler from pypy.module.test_lib_pypy.cffi_tests.udir import udir from pypy.module.test_lib_pypy.cffi_tests.support import u @@ -25,6 +25,9 @@ if 1: # test the .cpp mode too kwds.setdefault('source_extension', '.cpp') source = 'extern "C" {\n%s\n}' % (source,) + else: + kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) + + ['-Werror']) return recompiler._verify(ffi, module_name, source, *args, **kwds) @@ -1054,14 +1057,54 @@ assert lib.nu == 20 def test_some_float_type(): - py.test.skip("later") ffi = FFI() - ffi.cdef("typedef double... foo_t; foo_t sum(foo_t[]);") + ffi.cdef(""" + typedef double... foo_t; + typedef float... bar_t; + foo_t sum(foo_t[]); + bar_t neg(bar_t); + """) lib = verify(ffi, 'test_some_float_type', """ typedef float foo_t; static foo_t sum(foo_t x[]) { return x[0] + x[1]; } + typedef double bar_t; + static double neg(double x) { return -x; } """) assert lib.sum([40.0, 2.25]) == 42.25 + assert lib.sum([12.3, 45.6]) != 12.3 + 45.6 # precision loss + assert lib.neg(12.3) == -12.3 # no precision loss + assert ffi.sizeof("foo_t") == ffi.sizeof("float") + assert ffi.sizeof("bar_t") == ffi.sizeof("double") + +def test_some_float_invalid_1(): + ffi = FFI() + py.test.raises(FFIError, ffi.cdef, "typedef long double... foo_t;") + +def test_some_float_invalid_2(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_2', """ + typedef unsigned long foo_t; + foo_t neg(foo_t x) { return -x; } + """) + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type with an unexpected " + "size (or not a float type at all)") + +def test_some_float_invalid_3(): + ffi = FFI() + ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") + lib = verify(ffi, 'test_some_float_invalid_3', """ + typedef long double foo_t; + foo_t neg(foo_t x) { return -x; } + """) + if ffi.sizeof("long double") == ffi.sizeof("double"): + assert lib.neg(12.3) == -12.3 + else: + e = py.test.raises(ffi.error, getattr, lib, 'neg') + assert str(e.value) == ("primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") def test_issue200(): ffi = FFI() diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_zdist.py @@ -318,15 +318,32 @@ import cffi ffi = cffi.FFI() ffi.set_source("pack3.mymod", "/*code would be here*/") + ffi._hi_there = 42 """) with open("setup.py", "w") as f: - f.write("""if 1: + f.write("from __future__ import print_function\n" + """if 1: from setuptools import setup + from distutils.command.build_ext import build_ext + import os + + class TestBuildExt(build_ext): + def pre_run(self, ext, ffi): + print('_make_setuptools_api: in pre_run:', end=" ") + assert ffi._hi_there == 42 + assert ext.name == "pack3.mymod" + fn = os.path.join(os.path.dirname(self.build_lib), + '..', 'see_me') + print('creating %r' % (fn,)) + open(fn, 'w').close() + setup(name='example1', version='0.1', packages=['pack3'], package_dir={'': 'src1'}, - cffi_modules=["src1/pack3/_build.py:ffi"]) + cffi_modules=["src1/pack3/_build.py:ffi"], + cmdclass={'build_ext': TestBuildExt}, + ) """) @chdir_to_tmp @@ -335,6 +352,7 @@ self.run(["setup.py", "build"]) self.check_produced_files({'setup.py': None, 'build': '?', + 'see_me': None, 'src1': {'pack3': {'__init__.py': None, '_build.py': None}}}) @@ -344,6 +362,7 @@ self.run(["setup.py", "build_ext", "-i"]) self.check_produced_files({'setup.py': None, 'build': '?', + 'see_me': None, 'src1': {'pack3': {'__init__.py': None, '_build.py': None, 'mymod.SO': None}}}) diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -116,9 +116,6 @@ class AppTestLockSignals(GenericTestThread): pytestmark = py.test.mark.skipif("os.name != 'posix'") - def setup_class(cls): - cls.w_using_pthread_cond = cls.space.wrap(sys.platform == 'freebsd6') - def w_acquire_retries_on_intr(self, lock): import thread, os, signal, time self.sig_recvd = False @@ -157,8 +154,6 @@ raise KeyboardInterrupt def test_lock_acquire_interruption(self): - if self.using_pthread_cond: - skip('POSIX condition variables cannot be interrupted') import thread, signal, time # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck # in a deadlock. diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -3,7 +3,7 @@ indirection is introduced to make the version tag change less often. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( @@ -162,8 +162,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) wrapkey = _wrapkey diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -511,7 +511,7 @@ def getitervalues(self, w_dict): raise NotImplementedError - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): raise NotImplementedError has_iterreversed = False @@ -634,7 +634,7 @@ def getitervalues(self, w_dict): return iter([]) - def getiteritems(self, w_dict): + def getiteritems_with_hash(self, w_dict): return iter([]) def getiterreversed(self, w_dict): @@ -751,11 +751,11 @@ class IterClassItems(BaseItemIterator): def __init__(self, space, strategy, impl): - self.iterator = strategy.getiteritems(impl) + self.iterator = strategy.getiteritems_with_hash(impl) BaseIteratorImplementation.__init__(self, space, strategy, impl) def next_item_entry(self): - for key, value in self.iterator: + for key, value, keyhash in self.iterator: return (wrapkey(self.space, key), wrapvalue(self.space, value)) else: @@ -793,10 +793,10 @@ # the logic is to call prepare_dict_update() after the first setitem(): # it gives the w_updatedict a chance to switch its strategy. if 1: # (preserve indentation) - iteritems = self.getiteritems(w_dict) + iteritemsh = self.getiteritems_with_hash(w_dict) if not same_strategy(self, w_updatedict): # Different strategy. Try to copy one item of w_dict - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -807,7 +807,7 @@ w_updatedict.strategy.prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): - for key, value in iteritems: + for key, value, keyhash in iteritemsh: w_key = wrapkey(self.space, key) w_value = wrapvalue(self.space, value) w_updatedict.setitem(w_key, w_value) @@ -820,8 +820,8 @@ # wrapping/unwrapping the key. assert setitem_untyped is not None dstorage = w_updatedict.dstorage - for key, value in iteritems: - setitem_untyped(self, dstorage, key, value) + for key, value, keyhash in iteritemsh: + setitem_untyped(self, dstorage, key, value, keyhash) def same_strategy(self, w_otherdict): return (setitem_untyped is not None and @@ -945,8 +945,8 @@ def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).iteritems() + def getiteritems_with_hash(self, w_dict): + return objectmodel.iteritems_with_hash(self.unerase(w_dict.dstorage)) def getiterreversed(self, w_dict): return objectmodel.reversed_dict(self.unerase(w_dict.dstorage)) @@ -955,8 +955,9 @@ objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage), num_extra) - def setitem_untyped(self, dstorage, key, w_value): - self.unerase(dstorage)[key] = w_value + def setitem_untyped(self, dstorage, key, w_value, keyhash): + d = self.unerase(dstorage) + objectmodel.setitem_with_hash(d, key, keyhash, w_value) class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,4 +1,5 @@ from rpython.rlib import rerased +from rpython.rlib.objectmodel import iteritems_with_hash from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.dictmultiobject import ( @@ -103,8 +104,8 @@ return self.unerase(w_dict.dstorage).dict_w.iterkeys() def getitervalues(self, w_dict): return self.unerase(w_dict.dstorage).dict_w.itervalues() - def getiteritems(self, w_dict): - return self.unerase(w_dict.dstorage).dict_w.iteritems() + def getiteritems_with_hash(self, w_dict): + return iteritems_with_hash(self.unerase(w_dict.dstorage).dict_w) def wrapkey(space, key): return space.wrap(key) def wrapvalue(space, value): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -3,7 +3,7 @@ Based on two lists containing unwrapped key value pairs. """ -from rpython.rlib import jit, rerased +from rpython.rlib import jit, rerased, objectmodel from pypy.objspace.std.dictmultiobject import ( BytesDictStrategy, DictStrategy, EmptyDictStrategy, ObjectDictStrategy, @@ -165,13 +165,14 @@ def getitervalues(self, w_dict): return iter(self.unerase(w_dict.dstorage)[1]) - def getiteritems(self, w_dict): - return Zip(*self.unerase(w_dict.dstorage)) + def getiteritems_with_hash(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + return ZipItemsWithHash(keys, values_w) wrapkey = _wrapkey -class Zip(object): +class ZipItemsWithHash(object): def __init__(self, list1, list2): assert len(list1) == len(list2) self.list1 = list1 @@ -186,6 +187,7 @@ if i >= len(self.list1): raise StopIteration self.i = i + 1 - return (self.list1[i], self.list2[i]) + key = self.list1[i] + return (key, self.list2[i], objectmodel.compute_hash(key)) create_iterator_classes(KwargsDictStrategy) diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -8,6 +8,8 @@ from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict +from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash +from rpython.rlib.objectmodel import setitem_with_hash, delitem_with_hash from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit @@ -961,12 +963,12 @@ return self.erase(result_dict) def _difference_unwrapped(self, w_set, w_other): - iterator = self.unerase(w_set.sstorage).iterkeys() + self_dict = self.unerase(w_set.sstorage) other_dict = self.unerase(w_other.sstorage) result_dict = self.get_empty_dict() - for key in iterator: - if key not in other_dict: - result_dict[key] = None + for key, keyhash in iterkeys_with_hash(self_dict): + if not contains_with_hash(other_dict, key, keyhash): + setitem_with_hash(result_dict, key, keyhash, None) return self.erase(result_dict) def _difference_base(self, w_set, w_other): @@ -989,10 +991,10 @@ if w_set.sstorage is w_other.sstorage: my_dict.clear() return - iterator = self.unerase(w_other.sstorage).iterkeys() - for key in iterator: + other_dict = self.unerase(w_other.sstorage) + for key, keyhash in iterkeys_with_hash(other_dict): try: - del my_dict[key] + delitem_with_hash(my_dict, key, keyhash) except KeyError: pass @@ -1020,12 +1022,12 @@ d_new = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_other.keys(): - if not key in d_this: - d_new[key] = None - for key in d_this.keys(): - if not key in d_other: - d_new[key] = None + for key, keyhash in iterkeys_with_hash(d_other): + if not contains_with_hash(d_this, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) + for key, keyhash in iterkeys_with_hash(d_this): + if not contains_with_hash(d_other, key, keyhash): + setitem_with_hash(d_new, key, keyhash, None) storage = self.erase(d_new) return storage @@ -1105,9 +1107,9 @@ result = self.get_empty_dict() d_this = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_this: - if key in d_other: - result[key] = None + for key, keyhash in iterkeys_with_hash(d_this): + if contains_with_hash(d_other, key, keyhash): + setitem_with_hash(result, key, keyhash, None) return self.erase(result) def intersect(self, w_set, w_other): @@ -1125,9 +1127,10 @@ w_set.sstorage = storage def _issubset_unwrapped(self, w_set, w_other): + d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for item in self.unerase(w_set.sstorage): - if not item in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if not contains_with_hash(d_other, key, keyhash): return False return True @@ -1152,8 +1155,8 @@ def _isdisjoint_unwrapped(self, w_set, w_other): d_set = self.unerase(w_set.sstorage) d_other = self.unerase(w_other.sstorage) - for key in d_set: - if key in d_other: + for key, keyhash in iterkeys_with_hash(d_set): + if contains_with_hash(d_other, key, keyhash): return False return True diff --git a/pypy/tool/release/force-builds.py b/pypy/tool/release/force-builds.py --- a/pypy/tool/release/force-builds.py +++ b/pypy/tool/release/force-builds.py @@ -28,6 +28,7 @@ # 'pypy-c-app-level-win-x86-32', 'pypy-c-jit-linux-x86-32', 'pypy-c-jit-linux-x86-64', + 'pypy-c-jit-freebsd-9-x86-64', 'pypy-c-jit-macosx-x86-64', 'pypy-c-jit-win-x86-32', 'build-pypy-c-jit-linux-armhf-raring', @@ -42,7 +43,7 @@ import pwd return pwd.getpwuid(os.getuid())[0] -def main(branch, server): +def main(branch, server, user): #XXX: handle release tags #XXX: handle validity checks lock = defer.DeferredLock() @@ -56,7 +57,7 @@ print 'Forcing', builder, '...' url = "http://" + server + "/builders/" + builder + "/force" args = [ - ('username', get_user()), + ('username', user), ('revision', ''), ('forcescheduler', 'Force Scheduler'), ('submit', 'Force Build'), @@ -78,7 +79,8 @@ parser = optparse.OptionParser() parser.add_option("-b", "--branch", help="branch to build", default='') parser.add_option("-s", "--server", help="buildbot server", default="buildbot.pypy.org") + parser.add_option("-u", "--user", help="user name to report", default=get_user()) (options, args) = parser.parse_args() if not options.branch: parser.error("branch option required") - main(options.branch, options.server) + main(options.branch, options.server, user=options.user) diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh --- a/pypy/tool/release/repackage.sh +++ b/pypy/tool/release/repackage.sh @@ -1,12 +1,12 @@ # Edit these appropriately before running this script maj=2 min=6 -rev=0 +rev=1 # This script will download latest builds from the buildmaster, rename the top # level directory, and repackage ready to be uploaded to bitbucket. It will also # download source, assuming a tag for the release already exists, and repackage them. -for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 +for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 freebsd64 do wget http://buildbot.pypy.org/nightly/release-$maj.$min.x/pypy-c-jit-latest-$plat.tar.bz2 tar -xf pypy-c-jit-latest-$plat.tar.bz2 diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -520,26 +520,32 @@ return dic1.__class__(dic1.dictdef.union(dic2.dictdef)) +def _dict_can_only_throw_keyerror(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [KeyError] + +def _dict_can_only_throw_nothing(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + + class __extend__(pairtype(SomeDict, SomeObject)): - def _can_only_throw(dic1, *ignore): - if dic1.dictdef.dictkey.custom_eq_hash: - return None - return [KeyError] - def getitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) return dic1.dictdef.read_value() - getitem.can_only_throw = _can_only_throw + getitem.can_only_throw = _dict_can_only_throw_keyerror def setitem((dic1, obj2), s_value): dic1.dictdef.generalize_key(obj2) dic1.dictdef.generalize_value(s_value) - setitem.can_only_throw = _can_only_throw + setitem.can_only_throw = _dict_can_only_throw_nothing def delitem((dic1, obj2)): dic1.dictdef.generalize_key(obj2) - delitem.can_only_throw = _can_only_throw + delitem.can_only_throw = _dict_can_only_throw_keyerror class __extend__(pairtype(SomeTuple, SomeInteger)): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -4,6 +4,7 @@ from __future__ import absolute_import +from rpython.tool.pairtype import pair from rpython.flowspace.operation import op from rpython.flowspace.model import const, Constant from rpython.flowspace.argument import CallSpec @@ -11,11 +12,13 @@ SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue, - s_Bool, s_None, unionof, add_knowntypedata, + s_Bool, s_None, s_Int, unionof, add_knowntypedata, HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray) from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue from rpython.annotator import builtin from rpython.annotator.binaryop import _clone ## XXX where to put this? +from rpython.annotator.binaryop import _dict_can_only_throw_keyerror +from rpython.annotator.binaryop import _dict_can_only_throw_nothing from rpython.annotator.model import AnnotatorError from rpython.annotator.argument import simple_args, complex_args @@ -364,20 +367,19 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) -def _can_only_throw(s_dct, *ignore): - if s_dct.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - at op.contains.register(SomeDict) -def contains_SomeDict(annotator, dct, element): - annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) - if annotator.annotation(dct)._is_empty(): +def dict_contains(s_dct, s_element): + s_dct.dictdef.generalize_key(s_element) + if s_dct._is_empty(): s_bool = SomeBool() s_bool.const = False return s_bool return s_Bool -contains_SomeDict.can_only_throw = _can_only_throw + + at op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + return dict_contains(annotator.annotation(dct), + annotator.annotation(element)) +contains_SomeDict.can_only_throw = _dict_can_only_throw_nothing class __extend__(SomeDict): @@ -401,16 +403,22 @@ return self.dictdef.read_key() elif variant == 'values': return self.dictdef.read_value() - elif variant == 'items': + elif variant == 'items' or variant == 'items_with_hash': s_key = self.dictdef.read_key() s_value = self.dictdef.read_value() if (isinstance(s_key, SomeImpossibleValue) or isinstance(s_value, SomeImpossibleValue)): return s_ImpossibleValue - else: + elif variant == 'items': return SomeTuple((s_key, s_value)) - else: - raise ValueError + elif variant == 'items_with_hash': + return SomeTuple((s_key, s_value, s_Int)) + elif variant == 'keys_with_hash': + s_key = self.dictdef.read_key() + if isinstance(s_key, SomeImpossibleValue): + return s_ImpossibleValue + return SomeTuple((s_key, s_Int)) + raise ValueError(variant) def method_get(self, key, dfl): self.dictdef.generalize_key(key) @@ -448,6 +456,12 @@ def method_iteritems(self): return SomeIterator(self, 'items') + def method_iterkeys_with_hash(self): + return SomeIterator(self, 'keys_with_hash') + + def method_iteritems_with_hash(self): + return SomeIterator(self, 'items_with_hash') + def method_clear(self): pass @@ -460,6 +474,22 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() + def method_contains_with_hash(self, s_key, s_hash): + return dict_contains(self, s_key) + method_contains_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_setitem_with_hash(self, s_key, s_hash, s_value): + pair(self, s_key).setitem(s_value) + method_setitem_with_hash.can_only_throw = _dict_can_only_throw_nothing + + def method_getitem_with_hash(self, s_key, s_hash): + return pair(self, s_key).getitem() + method_getitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + + def method_delitem_with_hash(self, s_key, s_hash): + pair(self, s_key).delitem() + method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror + @op.contains.register(SomeString) @op.contains.register(SomeUnicodeString) def contains_String(annotator, string, char): diff --git a/rpython/doc/conf.py b/rpython/doc/conf.py --- a/rpython/doc/conf.py +++ b/rpython/doc/conf.py @@ -68,7 +68,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/rpython/jit/backend/arm/runner.py b/rpython/jit/backend/arm/runner.py --- a/rpython/jit/backend/arm/runner.py +++ b/rpython/jit/backend/arm/runner.py @@ -64,12 +64,6 @@ operations, original_loop_token, log=log) - def clear_latest_values(self, count): - setitem = self.assembler.fail_boxes_ptr.setitem - null = lltype.nullptr(llmemory.GCREF.TO) - for index in range(count): - setitem(index, null) - def cast_ptr_to_int(x): adr = llmemory.cast_ptr_to_adr(x) return CPU_ARM.cast_adr_to_int(adr) diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -212,8 +212,7 @@ self.codemap_builder.leave_portal_frame(op.getarg(0).getint(), self.mc.get_relative_pos()) - def call_assembler(self, op, guard_op, argloc, vloc, result_loc, tmploc): - self._store_force_index(guard_op) + def call_assembler(self, op, argloc, vloc, result_loc, tmploc): descr = op.getdescr() assert isinstance(descr, JitCellToken) # @@ -262,9 +261,6 @@ # # Here we join Path A and Path B again self._call_assembler_patch_jmp(jmp_location) - # XXX here should be emitted guard_not_forced, but due - # to incompatibilities in how it's done, we leave it for the - # caller to deal with @specialize.argtype(1) def _inject_debugging_code(self, looptoken, operations, tp, number): diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py --- a/rpython/jit/backend/llsupport/regalloc.py +++ b/rpython/jit/backend/llsupport/regalloc.py @@ -636,35 +636,29 @@ assert isinstance(box, Box) loc = self.fm.get_new_loc(box) locs.append(loc.value - base_ofs) - if looptoken.compiled_loop_token is not None: - # for tests + if looptoken.compiled_loop_token is not None: # <- for tests looptoken.compiled_loop_token._ll_initial_locs = locs - def can_merge_with_next_guard(self, op, i, operations): - if (op.getopnum() == rop.CALL_MAY_FORCE or - op.getopnum() == rop.CALL_ASSEMBLER or - op.getopnum() == rop.CALL_RELEASE_GIL): - assert operations[i + 1].getopnum() == rop.GUARD_NOT_FORCED - return True - if not op.is_comparison(): - if op.is_ovf(): - if (operations[i + 1].getopnum() != rop.GUARD_NO_OVERFLOW and - operations[i + 1].getopnum() != rop.GUARD_OVERFLOW): - not_implemented("int_xxx_ovf not followed by " - "guard_(no)_overflow") - return True + def next_op_can_accept_cc(self, operations, i): + op = operations[i] + next_op = operations[i + 1] + opnum = next_op.getopnum() + if (opnum != rop.GUARD_TRUE and opnum != rop.GUARD_FALSE + and opnum != rop.COND_CALL): return False - if (operations[i + 1].getopnum() != rop.GUARD_TRUE and - operations[i + 1].getopnum() != rop.GUARD_FALSE): + if next_op.getarg(0) is not op.result: return False - if operations[i + 1].getarg(0) is not op.result: + if self.longevity[op.result][1] > i + 1: return False - if (self.longevity[op.result][1] > i + 1 or - op.result in operations[i + 1].getfailargs()): - return False + if opnum != rop.COND_CALL: + if op.result in operations[i + 1].getfailargs(): + return False + else: + if op.result in operations[i + 1].getarglist()[1:]: + return False return True - def locs_for_call_assembler(self, op, guard_op): + def locs_for_call_assembler(self, op): descr = op.getdescr() assert isinstance(descr, JitCellToken) if op.numargs() == 2: diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2315,7 +2315,7 @@ value |= 32768 assert s.data.tid == value - def test_cond_call(self): + def test_cond_call_1(self): def func_void(*args): called.append(args) @@ -2352,6 +2352,51 @@ assert longlong.getrealfloat(self.cpu.get_float_value(frame, 6)) == 1.2 assert longlong.getrealfloat(self.cpu.get_float_value(frame, 7)) == 3.4 + def test_cond_call_2(self): + def func_void(*args): + called.append(args) + + FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void) + func_ptr = llhelper(lltype.Ptr(FUNC), func_void) + calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, + EffectInfo.MOST_GENERAL) + + for (operation, arg1, arg2_if_true, arg2_if_false) in [ + ('int_lt', -5, 2, -5), + ('int_le', 5, 5, -6), + ('int_eq', 11, 11, 12), + ('int_ne', 11, 12, 11), + ('int_gt', 8, -1, 8), + ('int_xor', 7, 3, 7), # test without a comparison at all + ('int_is_true', 4242, 1, 0), + ('int_is_zero', 4242, 0, 1), + ('float_lt', -0.5, 0.2, -0.5), + ('float_eq', 1.1, 1.1, 1.2), + ]: + called = [] + + ops = ''' + [%s, %s, i3, i4] + i2 = %s(%s) + cond_call(i2, ConstClass(func_ptr), i3, i4) + guard_no_exception(descr=faildescr) [] + finish() + ''' % ("i0" if operation.startswith('int') else "f0", + "i1" if operation.startswith('int') else "f1", + operation, + ("i1" if operation.startswith('int_is_') else + "i0, i1" if operation.startswith('int') else + "f0, f1")) + loop = parse(ops, namespace={'func_ptr': func_ptr, + 'faildescr': BasicFailDescr()}) + looptoken = JitCellToken() + self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) + frame = self.cpu.execute_token(looptoken, arg1, arg2_if_false, 0, 0) + assert called == [] + frame = self.cpu.execute_token(looptoken, arg1, arg2_if_true, + 67, 89) + assert called == [(67, 89)] + def test_force_operations_returning_void(self): values = [] def maybe_force(token, flag): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -114,10 +114,7 @@ def build_frame_realloc_slowpath(self): mc = codebuf.MachineCodeBlockWrapper() self._push_all_regs_to_frame(mc, [], self.cpu.supports_floats) - # this is the gcmap stored by push_gcmap(mov=True) in _check_stack_frame - mc.MOV_rs(ecx.value, WORD) - gcmap_ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.MOV_br(gcmap_ofs, ecx.value) + # the caller already did push_gcmap(store=True) if IS_X86_64: mc.MOV_rs(esi.value, WORD*2) @@ -147,7 +144,7 @@ self._load_shadowstack_top_in_ebx(mc, gcrootmap) mc.MOV_mr((ebx.value, -WORD), eax.value) - mc.MOV_bi(gcmap_ofs, 0) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], self.cpu.supports_floats) mc.RET() self._frame_realloc_slowpath = mc.materialize(self.cpu, []) @@ -164,6 +161,7 @@ # the end of this function. self._push_all_regs_to_frame(mc, cond_call_register_arguments + [eax], supports_floats, callee_only) + # the caller already did push_gcmap(store=True) if IS_X86_64: mc.SUB(esp, imm(WORD)) # alignment self.set_extra_stack_depth(mc, 2 * WORD) @@ -182,8 +180,8 @@ mc.ADD(esp, imm(WORD * 7)) self.set_extra_stack_depth(mc, 0) self._reload_frame_if_necessary(mc, align_stack=True) + self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only) - self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller mc.RET() return mc.materialize(self.cpu, []) @@ -203,10 +201,7 @@ assert kind in ['fixed', 'str', 'unicode', 'var'] mc = codebuf.MachineCodeBlockWrapper() self._push_all_regs_to_frame(mc, [eax, edi], self.cpu.supports_floats) - # store the gc pattern - ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') - mc.MOV_rs(ecx.value, WORD) - mc.MOV_br(ofs, ecx.value) + # the caller already did push_gcmap(store=True) # if kind == 'fixed': addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() @@ -258,8 +253,7 @@ self.set_extra_stack_depth(mc, 0) self._pop_all_regs_from_frame(mc, [eax, edi], self.cpu.supports_floats) mc.MOV(edi, heap(nursery_free_adr)) # load this in EDI - # clear the gc pattern - mc.MOV_bi(ofs, 0) + self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller mc.RET() # # If the slowpath malloc failed, we raise a MemoryError that @@ -646,7 +640,7 @@ jg_location = mc.get_relative_pos() mc.MOV_si(WORD, 0xffffff) # force writing 32 bit ofs2 = mc.get_relative_pos() - 4 - self.push_gcmap(mc, gcmap, mov=True) + self.push_gcmap(mc, gcmap, store=True) mc.CALL(imm(self._frame_realloc_slowpath)) # patch the JG above offset = mc.get_relative_pos() - jg_location @@ -732,8 +726,10 @@ def _assemble(self, regalloc, inputargs, operations): self._regalloc = regalloc + self.last_cc = rx86.cond_none regalloc.compute_hint_frame_locations(operations) regalloc.walk_operations(inputargs, operations) + assert self.last_cc == rx86.cond_none if we_are_translated() or self.cpu.dont_keepalive_stuff: self._regalloc = None # else keep it around for debugging frame_depth = regalloc.get_final_frame_depth() @@ -928,8 +924,8 @@ oopspecindex = effectinfo.oopspecindex genop_math_list[oopspecindex](self, op, arglocs, resloc) - def regalloc_perform_with_guard(self, op, guard_op, faillocs, - arglocs, resloc, frame_depth): + def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, + frame_depth): faildescr = guard_op.getdescr() assert isinstance(faildescr, AbstractFailDescr) failargs = guard_op.getfailargs() @@ -937,21 +933,12 @@ guard_token = self.implement_guard_recovery(guard_opnum, faildescr, failargs, faillocs, frame_depth) - if op is None: - dispatch_opnum = guard_opnum - else: - dispatch_opnum = op.getopnum() - genop_guard_list[dispatch_opnum](self, op, guard_op, guard_token, - arglocs, resloc) + genop_guard_list[guard_opnum](self, guard_op, guard_token, + arglocs, resloc) if not we_are_translated(): # must be added by the genop_guard_list[]() assert guard_token is self.pending_guard_tokens[-1] - def regalloc_perform_guard(self, guard_op, faillocs, arglocs, resloc, - frame_depth): - self.regalloc_perform_with_guard(None, guard_op, faillocs, arglocs, - resloc, frame_depth) - def load_effective_addr(self, sizereg, baseofs, scale, result, frm=imm0): self.mc.LEA(result, addr_add(frm, sizereg, baseofs, scale)) @@ -983,88 +970,70 @@ self.mc.LEA_rm(result_loc.value, (loc.value, delta)) return genop_binary_or_lea + def flush_cc(self, cond, result_loc): + # After emitting a instruction that leaves a boolean result in + # a condition code (cc), call this. In the common case, result_loc + # will be set to ebp by the regalloc, which in this case means + # "propagate it between this operation and the next guard by keeping + # it in the cc". In the uncommon case, result_loc is another + # register, and we emit a load from the cc into this register. + assert self.last_cc == rx86.cond_none + if result_loc is ebp: + self.last_cc = cond + else: + rl = result_loc.lowest8bits() + self.mc.SET_ir(cond, rl.value) + self.mc.MOVZX8_rr(result_loc.value, rl.value) + def _cmpop(cond, rev_cond): + cond = rx86.Conditions[cond] + rev_cond = rx86.Conditions[rev_cond] + # def genop_cmp(self, op, arglocs, result_loc): - rl = result_loc.lowest8bits() if isinstance(op.getarg(0), Const): self.mc.CMP(arglocs[1], arglocs[0]) - self.mc.SET_ir(rx86.Conditions[rev_cond], rl.value) + self.flush_cc(rev_cond, result_loc) else: self.mc.CMP(arglocs[0], arglocs[1]) - self.mc.SET_ir(rx86.Conditions[cond], rl.value) - self.mc.MOVZX8_rr(result_loc.value, rl.value) + self.flush_cc(cond, result_loc) return genop_cmp - def _cmpop_float(cond, rev_cond, is_ne=False): - def genop_cmp(self, op, arglocs, result_loc): - if isinstance(arglocs[0], RegLoc): + def _if_parity_clear_zero_and_carry(self): + self.mc.J_il8(rx86.Conditions['NP'], 0) + jnp_location = self.mc.get_relative_pos() + # CMP EBP, 0: as EBP cannot be null here, that operation should + # always clear zero and carry + self.mc.CMP_ri(ebp.value, 0) + # patch the JNP above + offset = self.mc.get_relative_pos() - jnp_location + assert 0 < offset <= 127 + self.mc.overwrite(jnp_location-1, chr(offset)) + + def _cmpop_float(cond, rev_cond): + is_ne = cond == 'NE' + need_direct_p = 'A' not in cond + need_rev_p = 'A' not in rev_cond + cond_contains_e = ('E' in cond) ^ ('N' in cond) + cond = rx86.Conditions[cond] + rev_cond = rx86.Conditions[rev_cond] + # + def genop_cmp_float(self, op, arglocs, result_loc): + if need_direct_p: + direct_case = not isinstance(arglocs[1], RegLoc) + else: + direct_case = isinstance(arglocs[0], RegLoc) + if direct_case: self.mc.UCOMISD(arglocs[0], arglocs[1]) checkcond = cond + need_p = need_direct_p else: self.mc.UCOMISD(arglocs[1], arglocs[0]) checkcond = rev_cond - - tmp1 = result_loc.lowest8bits() - if IS_X86_32: - tmp2 = result_loc.higher8bits() - elif IS_X86_64: - tmp2 = X86_64_SCRATCH_REG.lowest8bits() - - self.mc.SET_ir(rx86.Conditions[checkcond], tmp1.value) - if is_ne: - self.mc.SET_ir(rx86.Conditions['P'], tmp2.value) - self.mc.OR8_rr(tmp1.value, tmp2.value) - else: - self.mc.SET_ir(rx86.Conditions['NP'], tmp2.value) - self.mc.AND8_rr(tmp1.value, tmp2.value) - self.mc.MOVZX8_rr(result_loc.value, tmp1.value) - return genop_cmp - - def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond): - def genop_cmp_guard(self, op, guard_op, guard_token, arglocs, result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(op.getarg(0), Const): - self.mc.CMP(arglocs[1], arglocs[0]) - if guard_opnum == rop.GUARD_FALSE: - self.implement_guard(guard_token, rev_cond) - else: - self.implement_guard(guard_token, false_rev_cond) - else: - self.mc.CMP(arglocs[0], arglocs[1]) - if guard_opnum == rop.GUARD_FALSE: - self.implement_guard(guard_token, cond) - else: - self.implement_guard(guard_token, false_cond) - return genop_cmp_guard - - def _cmpop_guard_float(cond, rev_cond, false_cond, false_rev_cond): - need_direct_jp = 'A' not in cond - need_rev_jp = 'A' not in rev_cond - def genop_cmp_guard_float(self, op, guard_op, guard_token, arglocs, - result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(arglocs[0], RegLoc): - self.mc.UCOMISD(arglocs[0], arglocs[1]) - checkcond = cond - checkfalsecond = false_cond - need_jp = need_direct_jp - else: - self.mc.UCOMISD(arglocs[1], arglocs[0]) - checkcond = rev_cond - checkfalsecond = false_rev_cond - need_jp = need_rev_jp - if guard_opnum == rop.GUARD_FALSE: - if need_jp: - self.mc.J_il8(rx86.Conditions['P'], 6) - self.implement_guard(guard_token, checkcond) - else: - if need_jp: - self.mc.J_il8(rx86.Conditions['P'], 2) - self.mc.J_il8(rx86.Conditions[checkcond], 5) - self.implement_guard(guard_token) - else: - self.implement_guard(guard_token, checkfalsecond) - return genop_cmp_guard_float + need_p = need_rev_p + if need_p: + self._if_parity_clear_zero_and_carry() + self.flush_cc(checkcond, result_loc) + return genop_cmp_float def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: @@ -1127,37 +1096,17 @@ genop_ptr_eq = genop_instance_ptr_eq = genop_int_eq genop_ptr_ne = genop_instance_ptr_ne = genop_int_ne - genop_float_lt = _cmpop_float('B', 'A') - genop_float_le = _cmpop_float('BE', 'AE') - genop_float_ne = _cmpop_float('NE', 'NE', is_ne=True) - genop_float_eq = _cmpop_float('E', 'E') - genop_float_gt = _cmpop_float('A', 'B') - genop_float_ge = _cmpop_float('AE', 'BE') - genop_uint_gt = _cmpop("A", "B") genop_uint_lt = _cmpop("B", "A") genop_uint_le = _cmpop("BE", "AE") genop_uint_ge = _cmpop("AE", "BE") - genop_guard_int_lt = _cmpop_guard("L", "G", "GE", "LE") - genop_guard_int_le = _cmpop_guard("LE", "GE", "G", "L") - genop_guard_int_eq = _cmpop_guard("E", "E", "NE", "NE") - genop_guard_int_ne = _cmpop_guard("NE", "NE", "E", "E") - genop_guard_int_gt = _cmpop_guard("G", "L", "LE", "GE") - genop_guard_int_ge = _cmpop_guard("GE", "LE", "L", "G") - genop_guard_ptr_eq = genop_guard_instance_ptr_eq = genop_guard_int_eq - genop_guard_ptr_ne = genop_guard_instance_ptr_ne = genop_guard_int_ne - - genop_guard_uint_gt = _cmpop_guard("A", "B", "BE", "AE") - genop_guard_uint_lt = _cmpop_guard("B", "A", "AE", "BE") - genop_guard_uint_le = _cmpop_guard("BE", "AE", "A", "B") - genop_guard_uint_ge = _cmpop_guard("AE", "BE", "B", "A") - - genop_guard_float_lt = _cmpop_guard_float("B", "A", "AE","BE") - genop_guard_float_le = _cmpop_guard_float("BE","AE", "A", "B") - genop_guard_float_eq = _cmpop_guard_float("E", "E", "NE","NE") - genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE") - genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A") + genop_float_lt = _cmpop_float("B", "A") + genop_float_le = _cmpop_float("BE","AE") + genop_float_eq = _cmpop_float("E", "E") + genop_float_ne = _cmpop_float("NE", "NE") + genop_float_gt = _cmpop_float("A", "B") + genop_float_ge = _cmpop_float("AE","BE") def genop_math_sqrt(self, op, arglocs, resloc): self.mc.SQRTSD(arglocs[0], resloc) @@ -1187,20 +1136,6 @@ else: raise AssertionError("bad number of bytes") - def genop_guard_float_ne(self, op, guard_op, guard_token, arglocs, result_loc): - guard_opnum = guard_op.getopnum() - if isinstance(arglocs[0], RegLoc): - self.mc.UCOMISD(arglocs[0], arglocs[1]) - else: - self.mc.UCOMISD(arglocs[1], arglocs[0]) - if guard_opnum == rop.GUARD_TRUE: - self.mc.J_il8(rx86.Conditions['P'], 6) - self.implement_guard(guard_token, 'E') - else: - self.mc.J_il8(rx86.Conditions['P'], 2) - self.mc.J_il8(rx86.Conditions['E'], 5) - self.implement_guard(guard_token) - def genop_float_neg(self, op, arglocs, resloc): # Following what gcc does: res = x ^ 0x8000000000000000 self.mc.XORPD(arglocs[0], heap(self.float_const_neg_addr)) @@ -1247,33 +1182,20 @@ else: self.mov(loc0, resloc) - def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): - guard_opnum = guard_op.getopnum() - self.mc.CMP(arglocs[0], imm0) - if guard_opnum == rop.GUARD_TRUE: - self.implement_guard(guard_token, 'Z') + def test_location(self, loc): + assert not isinstance(loc, ImmedLoc) + if isinstance(loc, RegLoc): + self.mc.TEST_rr(loc.value, loc.value) # more compact else: - self.implement_guard(guard_token, 'NZ') + self.mc.CMP(loc, imm0) # works from memory too def genop_int_is_true(self, op, arglocs, resloc): - self.mc.CMP(arglocs[0], imm0) - rl = resloc.lowest8bits() - self.mc.SET_ir(rx86.Conditions['NE'], rl.value) - self.mc.MOVZX8(resloc, rl) - - def genop_guard_int_is_zero(self, op, guard_op, guard_token, arglocs, resloc): - guard_opnum = guard_op.getopnum() - self.mc.CMP(arglocs[0], imm0) - if guard_opnum == rop.GUARD_TRUE: - self.implement_guard(guard_token, 'NZ') - else: - self.implement_guard(guard_token, 'Z') + self.test_location(arglocs[0]) + self.flush_cc(rx86.Conditions['NZ'], resloc) From noreply at buildbot.pypy.org Fri Sep 11 18:13:20 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 11 Sep 2015 18:13:20 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: work in progress, adapting the transformation from pack -> vecop Message-ID: <20150911161320.DA73D1C11E0@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79593:cd37e9273b1b Date: 2015-09-11 18:13 +0200 http://bitbucket.org/pypy/pypy/changeset/cd37e9273b1b/ Log: work in progress, adapting the transformation from pack -> vecop diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -599,16 +599,6 @@ for guard_node in self.guards: self.build_guard_dependencies(guard_node, tracker) - def prepare_for_scheduling(self): - jump_node = self.nodes[len(self.nodes)-1] - jump_node.emitted = True - label_node = self.nodes[0] - for node in self.nodes: - if node.depends_count() == 0: - self.schedulable_nodes.insert(0, node) - if not we_are_translated(): - assert self.schedulable_nodes[-1] == label_node - def guard_argument_protection(self, guard_node, tracker): """ the parameters the guard protects are an indicator for dependencies. Consider the example: diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -1,6 +1,7 @@ from rpython.jit.metainterp.history import (VECTOR, FLOAT, INT, ConstInt, ConstFloat, TargetToken) -from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp) +from rpython.jit.metainterp.resoperation import (rop, ResOperation, + GuardResOp, VecOperation) from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.renamer import Renamer @@ -16,7 +17,8 @@ self.worklist = [] def post_schedule(self): - pass + loop = self.graph.loop + self.renamer.rename(loop.label.getoperation()) def profitable(self): return self.costmodel.profitable() @@ -24,15 +26,19 @@ def prepare(self): pass + def delay(self): + return False + def has_more(self): return len(self.worklist) > 0 class Scheduler(object): - """ The base class to be instantiated to (re)schedule a vector trace. """ + """ Create an instance of this class to (re)schedule a vector trace. """ def __init__(self): pass def next(self, state): + """ select the next candidate node to be emitted, or None """ worklist = state.worklist visited = 0 while len(worklist) > 0: @@ -41,79 +47,66 @@ node = worklist.pop() if node.emitted: continue - if self.schedulable(node): + if not self.delay(node, state): return node worklist.insert(0, node) visited += 1 return None - def schedulable(self, candidate): - """ Is the candidate scheduleable? Boils down to dependency_count == 0 - """ - if candidate.pack: - pack = candidate.pack - if pack.is_accumulating(): - for node in pack.operations: - for dep in node.depends(): - if dep.to.pack is not pack: - return False - return True - else: - for node in candidate.pack.operations: - if node.depends_count() > 0: - return False - return candidate.depends_count() == 0 + def delay(self, node, state): + """ Delay this operation? + Only if any dependency has not been resolved """ + if state.delay(node): + return True + return node.depends_count() != 0 - def scheduled(self, node, state): - """ Call this function if an operation has been emitted - adds new operations to the schedule list if - their dependency count drops to zero. - In addition it keeps the list sorted (see priority) - """ + def mark_emitted(self, node, state): + """ An operation has been emitted, adds new operations to the worklist + whenever their dependency count drops to zero. + Keeps worklist sorted (see priority) """ + op = node.getoperation() state.renamer.rename(op) state.unpack_from_vector(op, self) - node.position = len(self.oplist) + node.position = len(state.oplist) + worklist = state.worklist for dep in node.provides()[:]: # COPY to = dep.to node.remove_edge_to(to) - nodes = self.schedulable_nodes if not to.emitted and to.depends_count() == 0: # sorts them by priority - i = len(nodes)-1 + i = len(worklist)-1 while i >= 0: - itnode = nodes[i] + itnode = worklist[i] c = (itnode.priority - to.priority) if c < 0: # meaning itnode.priority < to.priority: - nodes.insert(i+1, to) + worklist.insert(i+1, to) break elif c == 0: # if they have the same priority, sort them # using the original position in the trace if itnode.getindex() < to.getindex(): - nodes.insert(i, to) + worklist.insert(i, to) break i -= 1 else: - nodes.insert(0, to) + worklist.insert(0, to) node.clear_dependencies() node.emitted = True def walk_and_emit(self, state): # TODO oplist, renamer, unpack=False): """ Emit all the operations into the oplist parameter. - Initiates the scheduling. - """ + Initiates the scheduling. """ assert isinstance(state, SchedulerState) while state.has_more(): node = self.next(state) if node: - if not state.emit(node): + if not state.emit(node, self): if not node.emitted: op = node.getoperation() - scheduler.scheduled(node, state) + self.mark_emitted(node, state) + state.oplist.append(op) continue - - # it happens that packs can emit many nodes that have been # added to the scheuldable_nodes list, in this case it could # be that no next exists even though the list contains elements @@ -122,13 +115,9 @@ raise AssertionError("schedule failed cannot continue. possible reason: cycle") - # TODO - #jump_node = self.graph.nodes[-1] - #jump_op = jump_node.getoperation() - #renamer.rename(jump_op) - #assert jump_op.getopnum() == rop.JUMP - #self.sched_data.unpack_from_vector(jump_op, self) - #oplist.append(jump_op) + if not we_are_translated(): + for node in state.graph.nodes: + assert node.emitted def vectorbox_outof_box(box, count=-1, size=-1, type='-'): if box.type not in (FLOAT, INT): @@ -140,12 +129,12 @@ def packtype_outof_box(box): if box.type == VECTOR: - return PackType.of(box) + return Type.of(box) else: if box.type == INT: - return PackType(INT, 8, True, 2) + return Type(INT, 8, True, 2) elif box.type == FLOAT: - return PackType(FLOAT, 8, False, 2) + return Type(FLOAT, 8, False, 2) # raise AssertionError("box %s not supported" % (box,)) @@ -184,121 +173,230 @@ # raise AssertionError("getexpandopnum type %s not supported" % (type,)) -class PackType(object): - """ Represents the type of an operation (either it's input or - output). - """ - UNKNOWN_TYPE = '-' +UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, + rop.UINT_LT, rop.UINT_LE, + rop.UINT_GT, rop.UINT_GE) +class Type(object): + """ The type of one operation. Saves type, size and sign. """ @staticmethod - def of(box, count=-1): - assert box.type == 'V' - if count == -1: - count = box.getcount() - return PackType(box.gettype(), box.getsize(), box.getsigned(), count) + def of(op): + descr = op.getdescr() + if descr: + type = INT + if descr.is_array_of_floats() or descr.concrete_type == FLOAT: + type = FLOAT + size = descr.get_item_size_in_bytes() + sign = descr.is_item_signed() + return Type(type, size, sign) + else: + size = 8 + sign = True + if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: + sign = False + return Type(op.type, size, sign) - @staticmethod - def by_descr(descr, vec_reg_size): - _t = INT - signed = descr.is_item_signed() - if descr.is_array_of_floats() or descr.concrete_type == FLOAT: - _t = FLOAT - signed = False - size = descr.get_item_size_in_bytes() - pt = PackType(_t, size, signed, vec_reg_size // size) - return pt - - def __init__(self, type, size, signed, count=-1): - assert type in (FLOAT, INT, PackType.UNKNOWN_TYPE) + def __init__(self, type, size, signed): + assert type in (FLOAT, INT) self.type = type self.size = size self.signed = signed + + def clone(self): + return Type(self.type, self.size, self.signed) + + def __repr__(self): + sign = '-' + if not self.signed: + sign = '+' + return 'Type(%s%s, %d)' % (sign, self.type, self.size) + + #UNKNOWN_TYPE = '-' + + #@staticmethod + #def of(box, count=-1): + # assert box.type == 'V' + # if count == -1: + # count = box.getcount() + # return Type(box.gettype(), box.getsize(), box.getsigned(), count) + + #@staticmethod + #def by_descr(descr, vec_reg_size): + # _t = INT + # signed = descr.is_item_signed() + # if descr.is_array_of_floats() or descr.concrete_type == FLOAT: + # _t = FLOAT + # signed = False + # size = descr.get_item_size_in_bytes() + # pt = Type(_t, size, signed, vec_reg_size // size) + # return pt + + #def clone(self): + # return Type(self.type, self.size, self.signed, self.count) + + #def new_vector_box(self, count = -1): + # if count == -1: + # count = self.count + # assert count > 1 + # assert self.type in ('i','f') + # assert self.size > 0 + # xxx + # return BoxVector(self.type, count, self.size, self.signed) + + #def combine(self, other): + # """ nothing to be done here """ + # if not we_are_translated(): + # assert self.type == other.type + # assert self.signed == other.signed + + + #def byte_size(self): + # return self.count * self.size + + #def setsize(self, size): + # self.size = size + + #def setcount(self, count): + # self.count = count + + #def gettype(self): + # return self.type + + #def getsize(self): + # return self.size + + #def getcount(self): + # return self.count + + #def pack_byte_size(self, pack): + # if len(pack.operations) == 0: + # return 0 + # return self.getsize() * pack.opcount() + +class TypeRestrict(object): + ANY_TYPE = -1 + ANY_SIZE = -1 + ANY_SIGN = -1 + ANY_COUNT = -1 + SIGNED = 1 + UNSIGNED = 0 + + def __init__(self, type=-1, bytesize=-1, count=-1, sign=-1): + self.type = type + self.bytesize = bytesize + self.sign = sign self.count = count - def clone(self): - return PackType(self.type, self.size, self.signed, self.count) + def allows(self, type, count): + if self.type != ANY_TYPE: + if self.type != type.type: + return False - def new_vector_box(self, count = -1): - if count == -1: - count = self.count - assert count > 1 - assert self.type in ('i','f') - assert self.size > 0 - xxx - return BoxVector(self.type, count, self.size, self.signed) + # TODO - def combine(self, other): - """ nothing to be done here """ - if not we_are_translated(): - assert self.type == other.type - assert self.signed == other.signed + return True - def __repr__(self): - return 'PackType(%s, %d, %d, #%d)' % (self.type, self.size, self.signed, self.count) - - def byte_size(self): - return self.count * self.size - - def setsize(self, size): - self.size = size - - def setcount(self, count): +class TypeOutput(object): + def __init__(self, type, count): + self.type = type self.count = count - def gettype(self): - return self.type - - def getsize(self): - return self.size - - def getcount(self): - return self.count - - def pack_byte_size(self, pack): - if len(pack.operations) == 0: - return 0 - return self.getsize() * pack.opcount() - - -PT_GENERIC = PackType(PackType.UNKNOWN_TYPE, -1, False) -PT_FLOAT_2 = PackType(FLOAT, 4, False, 2) -PT_DOUBLE_2 = PackType(FLOAT, 8, False, 2) -PT_FLOAT_GENERIC = PackType(INT, -1, False) -PT_INT64 = PackType(INT, 8, True) -PT_INT32_2 = PackType(INT, 4, True, 2) -PT_INT_GENERIC = PackType(INT, -1, True) - -INT_RES = PT_INT_GENERIC -FLOAT_RES = PT_FLOAT_GENERIC +class PassFirstArg(TypeOutput): + def __init__(self): + pass class OpToVectorOp(object): - def __init__(self, arg_ptypes, result_ptype): - self.arg_ptypes = [a for a in arg_ptypes] # do not use a tuple. rpython cannot union - self.result_ptype = result_ptype - self.vecops = None - self.sched_data = None - self.pack = None - self.input_type = None - self.output_type = None - self.costmodel = None + def __init__(self, restrictargs, typeoutput): + self.args = list(restrictargs) # do not use a tuple. rpython cannot union + self.out = typeoutput - def as_vector_operation(self, pack, sched_data, scheduler, oplist): - self.sched_data = sched_data - self.vecops = oplist - self.costmodel = sched_data.costmodel - self.input_type = pack.input_type - self.output_type = pack.output_type + def as_vector_operation(self, state, pack): # - self.check_if_pack_supported(pack) - self.pack = pack - self.transform_pack() + # TODO self.check_if_pack_supported(pack) + op = pack.leftmost() + args = op.getarglist() + self.prepare_arguments(state, op.getarglist()) # - self.pack = None - self.costmodel = None - self.vecops = None - self.sched_data = None - self.input_type = None - self.output_type = None + vop = VecOperation(op.vector, args, otype. op.getdescr()) + #result = self.transform_result(op) + # + if op.is_guard(): + assert isinstance(op, GuardResOp) + assert isinstance(vop, GuardResOp) + vop.setfailargs(op.getfailargs()) + vop.rd_snapshot = op.rd_snapshot + self.vecops.append(vop) + self.costmodel.record_pack_savings(self.pack, self.pack.opcount()) + # + if pack.is_accumulating(): + box = oplist[position].result + assert box is not None + for node in pack.operations: + op = node.getoperation() + assert not op.returns_void() + scheduler.renamer.start_renaming(op, box) + + def transform_arguments(self, state, args): + self.before_argument_transform(args) + # Transforming one argument to a vector box argument + # The following cases can occur: + # 1) argument is present in the box_to_vbox map. + # a) vector can be reused immediatly (simple case) + # b) vector is to big + # c) vector is to small + # 2) argument is not known to reside in a vector + # a) expand vars/consts before the label and add as argument + # b) expand vars created in the loop body + # + for i,arg in enumerate(args): + if arg.returns_vector(): + continue + if not self.transform_arg_at(i): + continue + box_pos, vbox = state.getvector_of_box(arg) + if not vbox: + # 2) constant/variable expand this box + vbox = self.expand(arg, i) + self.sched_data.setvector_of_box(arg, 0, vbox) + box_pos = 0 + # convert size i64 -> i32, i32 -> i64, ... + if self.input_type.getsize() > 0 and \ + self.input_type.getsize() != vbox.getsize(): + vbox = self.extend(vbox, self.input_type) + + # use the input as an indicator for the pack type + packable = self.input_type.getcount() + packed = vbox.getcount() + assert packed >= 0 + assert packable >= 0 + if packed > packable: + # the argument has more items than the operation is able to process! + # box_pos == 0 then it is already at the right place + if box_pos != 0: + args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) + self.update_arg_in_vector_pos(i, args[i]) + #self.update_input_output(self.pack) + continue + else: + assert vbox is not None + args[i] = vbox + continue + vboxes = self.vector_boxes_for_args(i) + if packed < packable and len(vboxes) > 1: + # the argument is scattered along different vector boxes + args[i] = self.gather(vboxes, packable) + self.update_arg_in_vector_pos(i, args[i]) + continue + if box_pos != 0: + # The vector box is at a position != 0 but it + # is required to be at position 0. Unpack it! + args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) + self.update_arg_in_vector_pos(i, args[i]) + continue + #self.update_input_output(self.pack) + # + assert vbox is not None + args[i] = vbox def before_argument_transform(self, args): pass @@ -319,25 +417,6 @@ # see assembler for comment why raise NotAProfitableLoop - - def transform_pack(self): - """ High level transformation routine of a pack to operations """ - op = self.pack.leftmost() - args = op.getarglist() - self.before_argument_transform(args) - self.transform_arguments(args) - # - vop = ResOperation(op.vector, args, op.getdescr()) - #result = self.transform_result(op) - # - if op.is_guard(): - assert isinstance(op, GuardResOp) - assert isinstance(vop, GuardResOp) - vop.setfailargs(op.getfailargs()) - vop.rd_snapshot = op.rd_snapshot - self.vecops.append(vop) - self.costmodel.record_pack_savings(self.pack, self.pack.opcount()) - def transform_result(self, result): if result is None: return None @@ -571,10 +650,10 @@ variables.append(vbox) return vbox - def is_vector_arg(self, i): - if i < 0 or i >= len(self.arg_ptypes): + def transform_arg_at(self, i): + if i < 0 or i >= len(self.args): return False - return self.arg_ptypes[i] is not None + return self.args[i] is not None def get_output_type_given(self, input_type, op): return input_type @@ -590,9 +669,10 @@ class OpToVectorOpConv(OpToVectorOp): def __init__(self, intype, outtype): - self.from_size = intype.getsize() - self.to_size = outtype.getsize() - OpToVectorOp.__init__(self, (intype, ), outtype) + #self.from_size = intype.getsize() + #self.to_size = outtype.getsize() + #OpToVectorOp.__init__(self, (intype, ), outtype) + pass def new_result_vector_box(self): type = self.output_type.gettype() @@ -650,14 +730,14 @@ class LoadToVectorLoad(OpToVectorOp): def __init__(self): - OpToVectorOp.__init__(self, (), PT_GENERIC) + OpToVectorOp.__init__(self, (), TypeRestrict()) def before_argument_transform(self, args): count = min(self.output_type.getcount(), len(self.getoperations())) args.append(ConstInt(count)) def get_output_type_given(self, input_type, op): - return PackType.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) def get_input_type_given(self, output_type, op): return None @@ -668,7 +748,7 @@ Thus a modified split_pack function. """ def __init__(self): - OpToVectorOp.__init__(self, (None, None, PT_GENERIC), None) + OpToVectorOp.__init__(self, (None, None, TypeRestrict()), None) self.has_descr = True def must_be_full_but_is_not(self, pack): @@ -680,7 +760,7 @@ return None def get_input_type_given(self, output_type, op): - return PackType.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) class PassThroughOp(OpToVectorOp): """ This pass through is only applicable if the target @@ -696,55 +776,68 @@ def get_input_type_given(self, output_type, op): raise AssertionError("cannot infer input type from output type") -GUARD_TF = PassThroughOp((PT_INT_GENERIC,)) -INT_OP_TO_VOP = OpToVectorOp((PT_INT_GENERIC, PT_INT_GENERIC), INT_RES) -FLOAT_OP_TO_VOP = OpToVectorOp((PT_FLOAT_GENERIC, PT_FLOAT_GENERIC), FLOAT_RES) -FLOAT_SINGLE_ARG_OP_TO_VOP = OpToVectorOp((PT_FLOAT_GENERIC,), FLOAT_RES) -LOAD_TRANS = LoadToVectorLoad() -STORE_TRANS = StoreToVectorStore() -# note that the following definition is x86 arch specific -ROP_ARG_RES_VECTOR = { - rop.VEC_INT_ADD: INT_OP_TO_VOP, - rop.VEC_INT_SUB: INT_OP_TO_VOP, - rop.VEC_INT_MUL: INT_OP_TO_VOP, - rop.VEC_INT_AND: INT_OP_TO_VOP, - rop.VEC_INT_OR: INT_OP_TO_VOP, - rop.VEC_INT_XOR: INT_OP_TO_VOP, +class trans(object): + PASS = PassFirstArg() - rop.VEC_INT_EQ: INT_OP_TO_VOP, - rop.VEC_INT_NE: INT_OP_TO_VOP, + TR_ANY_FLOAT = TypeRestrict(FLOAT) + TR_ANY_INTEGER = TypeRestrict(INT) + TR_FLOAT_2 = TypeRestrict(FLOAT, 4, 2) + TR_DOUBLE_2 = TypeRestrict(FLOAT, 8, 2) + TR_LONG = TypeRestrict(INT, 8, 2) + TR_INT_2 = TypeRestrict(INT, 4, 2) - rop.VEC_INT_SIGNEXT: SignExtToVectorOp((PT_INT_GENERIC,), INT_RES), + INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), PASS) + FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), PASS) + FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), PASS) + LOAD = LoadToVectorLoad() + STORE = StoreToVectorStore() + GUARD = PassThroughOp((TR_ANY_INTEGER,)) - rop.VEC_FLOAT_ADD: FLOAT_OP_TO_VOP, - rop.VEC_FLOAT_SUB: FLOAT_OP_TO_VOP, - rop.VEC_FLOAT_MUL: FLOAT_OP_TO_VOP, - rop.VEC_FLOAT_TRUEDIV: FLOAT_OP_TO_VOP, - rop.VEC_FLOAT_ABS: FLOAT_SINGLE_ARG_OP_TO_VOP, - rop.VEC_FLOAT_NEG: FLOAT_SINGLE_ARG_OP_TO_VOP, - rop.VEC_FLOAT_EQ: OpToVectorOp((PT_FLOAT_GENERIC,PT_FLOAT_GENERIC), INT_RES), - rop.VEC_FLOAT_NE: OpToVectorOp((PT_FLOAT_GENERIC,PT_FLOAT_GENERIC), INT_RES), - rop.VEC_INT_IS_TRUE: OpToVectorOp((PT_INT_GENERIC,PT_INT_GENERIC), PT_INT_GENERIC), + # note that the following definition is x86 arch specific + MAPPING = { + rop.VEC_INT_ADD: INT, + rop.VEC_INT_SUB: INT, + rop.VEC_INT_MUL: INT, + rop.VEC_INT_AND: INT, + rop.VEC_INT_OR: INT, + rop.VEC_INT_XOR: INT, + rop.VEC_INT_EQ: INT, + rop.VEC_INT_NE: INT, - rop.VEC_RAW_LOAD_I: LOAD_TRANS, - rop.VEC_RAW_LOAD_F: LOAD_TRANS, - rop.VEC_GETARRAYITEM_RAW_I: LOAD_TRANS, - rop.VEC_GETARRAYITEM_RAW_F: LOAD_TRANS, - rop.VEC_GETARRAYITEM_GC_I: LOAD_TRANS, - rop.VEC_GETARRAYITEM_GC_F: LOAD_TRANS, - rop.VEC_RAW_STORE: STORE_TRANS, - rop.VEC_SETARRAYITEM_RAW: STORE_TRANS, - rop.VEC_SETARRAYITEM_GC: STORE_TRANS, + rop.VEC_FLOAT_ADD: FLOAT, + rop.VEC_FLOAT_SUB: FLOAT, + rop.VEC_FLOAT_MUL: FLOAT, + rop.VEC_FLOAT_TRUEDIV: FLOAT, + rop.VEC_FLOAT_ABS: FLOAT_UNARY, + rop.VEC_FLOAT_NEG: FLOAT_UNARY, - rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: OpToVectorOpConv(PT_DOUBLE_2, PT_FLOAT_2), - rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: OpToVectorOpConv(PT_FLOAT_2, PT_DOUBLE_2), - rop.VEC_CAST_FLOAT_TO_INT: OpToVectorOpConv(PT_DOUBLE_2, PT_INT32_2), - rop.VEC_CAST_INT_TO_FLOAT: OpToVectorOpConv(PT_INT32_2, PT_DOUBLE_2), + rop.VEC_RAW_LOAD_I: LOAD, + rop.VEC_RAW_LOAD_F: LOAD, + rop.VEC_GETARRAYITEM_RAW_I: LOAD, + rop.VEC_GETARRAYITEM_RAW_F: LOAD, + rop.VEC_GETARRAYITEM_GC_I: LOAD, + rop.VEC_GETARRAYITEM_GC_F: LOAD, - rop.GUARD_TRUE: GUARD_TF, - rop.GUARD_FALSE: GUARD_TF, -} + rop.VEC_RAW_STORE: STORE, + rop.VEC_SETARRAYITEM_RAW: STORE, + rop.VEC_SETARRAYITEM_GC: STORE, + + rop.GUARD_TRUE: GUARD, + rop.GUARD_FALSE: GUARD, + + # irregular + rop.VEC_INT_SIGNEXT: SignExtToVectorOp((TR_ANY_INTEGER,), None), + + rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: OpToVectorOpConv(TR_DOUBLE_2, None), #RESTRICT_2_FLOAT), + rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: OpToVectorOpConv(TR_FLOAT_2, None), #RESTRICT_2_DOUBLE), + rop.VEC_CAST_FLOAT_TO_INT: OpToVectorOpConv(TR_DOUBLE_2, None), #RESTRICT_2_INT), + rop.VEC_CAST_INT_TO_FLOAT: OpToVectorOpConv(TR_INT_2, None), #RESTRICT_2_DOUBLE), + + rop.VEC_FLOAT_EQ: OpToVectorOp((TR_ANY_FLOAT,TR_ANY_FLOAT), None), + rop.VEC_FLOAT_NE: OpToVectorOp((TR_ANY_FLOAT,TR_ANY_FLOAT), None), + rop.VEC_INT_IS_TRUE: OpToVectorOp((TR_ANY_INTEGER,TR_ANY_INTEGER), None), # TR_ANY_INTEGER), + } def determine_input_output_types(pack, node, forward): """ This function is two fold. If moving forward, it @@ -772,7 +865,7 @@ return input_type, output_type def determine_trans(op): - op2vecop = ROP_ARG_RES_VECTOR.get(op.vector, None) + op2vecop = trans.MAPPING.get(op.vector, None) if op2vecop is None: raise NotImplementedError("missing vecop for '%s'" % (op.getopname(),)) return op2vecop @@ -794,28 +887,27 @@ self.seen = {} def post_schedule(self): - pass - # TODO label rename - if vector: - # XXX - # add accumulation info to the descriptor - #for version in self.loop.versions: - # # this needs to be done for renamed (accum arguments) - # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] - #self.appended_arg_count = len(sched_data.invariant_vector_vars) - ##for guard_node in graph.guards: - ## op = guard_node.getoperation() - ## failargs = op.getfailargs() - ## for i,arg in enumerate(failargs): - ## if arg is None: - ## continue - ## accum = arg.getaccum() - ## if accum: - ## pass - ## #accum.save_to_descr(op.getdescr(),i) - #self.has_two_labels = len(sched_data.invariant_oplist) > 0 - #self.loop.operations = self.prepend_invariant_operations(sched_data) - pass + loop = self.graph.loop + self.sched_data.unpack_from_vector(loop.jump.getoperation(), self) + SchedulerState.post_schedule(self) + + # add accumulation info to the descriptor + #for version in self.loop.versions: + # # this needs to be done for renamed (accum arguments) + # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] + #self.appended_arg_count = len(sched_data.invariant_vector_vars) + ##for guard_node in graph.guards: + ## op = guard_node.getoperation() + ## failargs = op.getfailargs() + ## for i,arg in enumerate(failargs): + ## if arg is None: + ## continue + ## accum = arg.getaccum() + ## if accum: + ## pass + ## #accum.save_to_descr(op.getdescr(),i) + #self.has_two_labels = len(sched_data.invariant_oplist) > 0 + #self.loop.operations = self.prepend_invariant_operations(sched_data) def profitable(self): @@ -823,7 +915,10 @@ def prepare(self): SchedulerState.prepare(self) - self.graph.prepare_for_scheduling() + for node in self.graph.nodes: + if node.depends_count() == 0: + self.worklist.insert(0, node) + self.packset.accumulate_prepare(self) for arg in self.graph.loop.label.getarglist(): self.seen[arg] = None @@ -834,32 +929,26 @@ """ if node.pack: for node in node.pack.operations: - scheduler.scheduled(node) - self.as_vector_operation(node.pack) + scheduler.mark_emitted(node, self) + assert node.pack.opcount() > 1 + op2vecop = determine_trans(node.pack.leftmost()) + op2vecop.as_vector_operation(self, node.pack) return True return False - - def as_vector_operation(self, pack): - """ Transform a pack into a single or several operation. - Calls the as_vector_operation of the OpToVectorOp implementation. - """ - assert pack.opcount() > 1 - # properties that hold for the pack are: - # + isomorphism (see func) - # + tightly packed (no room between vector elems) - - position = len(self.oplist) - op = pack.leftmost().getoperation() - determine_trans(op).as_vector_operation(pack, self, self.oplist) - # - if pack.is_accumulating(): - box = oplist[position].result - assert box is not None - for node in pack.operations: - op = node.getoperation() - assert not op.returns_void() - scheduler.renamer.start_renaming(op, box) + def delay(self, node): + if node.pack: + pack = node.pack + if pack.is_accumulating(): + for node in pack.operations: + for dep in node.depends(): + if dep.to.pack is not pack: + return True + else: + for node in pack.operations: + if node.depends_count() > 0: + return True + return False def unpack_from_vector(self, op, scheduler): """ If a box is needed that is currently stored within a vector diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -7,7 +7,7 @@ Pack, Pair, NotAProfitableLoop, VectorizingOptimizer, X86_CostModel, PackSet) from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph -from rpython.jit.metainterp.optimizeopt.schedule import PackType, Scheduler +from rpython.jit.metainterp.optimizeopt.schedule import Type, Scheduler from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest, FakeDependencyGraph) @@ -17,13 +17,13 @@ from rpython.jit.tool.oparser import parse as opparse from rpython.jit.tool.oparser_model import get_model -F64 = PackType('f',8,False,2) -F32 = PackType('f',4,False,4) -F32_2 = PackType('f',4,False,2) -I64 = PackType('i',8,True,2) -I32 = PackType('i',4,True,4) -I32_2 = PackType('i',4,True,2) -I16 = PackType('i',2,True,8) +F64 = Type('f',8,False) +F32 = Type('f',4,False) +F32_2 = Type('f',4,False) +I64 = Type('i',8,True) +I32 = Type('i',4,True) +I32_2 = Type('i',4,True) +I16 = Type('i',2,True) class FakePackSet(PackSet): def __init__(self, packs): @@ -77,7 +77,6 @@ pairs = [] for pack in packs: for i in range(len(pack.operations)-1): - pack.clear() o1 = pack.operations[i] o2 = pack.operations[i+1] pair = Pair(o1,o2,pack.input_type,pack.output_type) @@ -100,10 +99,10 @@ def test_next_must_not_loop_forever(self): scheduler = Scheduler() - def schedulable(node): + def delay(node, state): node.count += 1 - return False - scheduler.schedulable = schedulable + return True + scheduler.delay = delay class State(object): pass class Node(object): emitted = False; pack = None; count = 0 state = State() @@ -269,7 +268,7 @@ """) pack1 = self.pack(loop1, 0, 8, None, F64) pack2 = self.pack(loop1, 8, 16, F64, I32_2) - I16_2 = PackType('i',2,True,2) + I16_2 = Type('i',2,True) pack3 = self.pack(loop1, 16, 24, I32_2, I16_2) pack4 = self.pack(loop1, 24, 32, I16, None) def void(b,c): diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -22,7 +22,7 @@ from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, - getunpackopnum, PackType, determine_input_output_types) + getunpackopnum, Type, determine_input_output_types) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) from rpython.rlib import listsort @@ -449,21 +449,12 @@ if fail: assert False - def schedule(self, state): # TODO vector=False, sched_data=None): - """ Scheduling the trace and emitting vector operations - for packed instructions. - """ + def schedule(self, state): state.prepare() scheduler = Scheduler() scheduler.walk_and_emit(state) - # - if not we_are_translated(): - for node in graph.nodes: - assert node.emitted - # if state.profitable(): return - # state.post_schedule() def prepend_invariant_operations(self, sched_data): @@ -681,14 +672,13 @@ return None # if origin_pack is None: - descr = lnode.getoperation().getdescr() - ptype = PackType.by_descr(descr, self.vec_reg_size) - if lnode.getoperation().is_primitive_load(): + op = lnode.getoperation() + if op.is_primitive_load(): # load outputs value, no input - return Pair(lnode, rnode, None, ptype) + return Pair(lnode, rnode, None, Type.of(op)) else: # store only has an input - return Pair(lnode, rnode, ptype, None) + return Pair(lnode, rnode, Type.of(op), None) if self.profitable_pack(lnode, rnode, origin_pack, forward): input_type, output_type = \ determine_input_output_types(origin_pack, lnode, forward) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -82,6 +82,11 @@ op.setdescr(descr) return op +def VecOperation(opnum, args, type, count, descr=None): + op = ResOperation(opnum, args, descr) + op.item_type = type + op.item_count = count + return op class AbstractResOpOrInputArg(AbstractValue): _attrs_ = ('_forwarded',) @@ -90,8 +95,6 @@ def get_forwarded(self): return self._forwarded - - class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" @@ -555,8 +558,8 @@ class VectorOp(object): _mixin_ = True - _attrs_ = ('item_type','item_count','item_size','item_signed','accum') - _extended_display = False + #_attrs_ = ('item_type','item_count','item_size','item_signed','accum') + _attrs_ = ('item_type', 'item_count') #def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): # assert item_type in (FLOAT, INT) @@ -567,13 +570,10 @@ # self.accum = None def gettype(self): - return self.item_type + return self.type - def getsize(self): - return self.item_size - - def getsigned(self): - return self.item_signed + def getbytes(self): + return self.slot_bytes def getcount(self): return self.item_count From noreply at buildbot.pypy.org Sat Sep 12 20:28:36 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 12 Sep 2015 20:28:36 +0200 (CEST) Subject: [pypy-commit] pypy default: fix more tests Message-ID: <20150912182836.E2CC31C130D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79594:f94114913cc0 Date: 2015-09-12 21:28 +0300 http://bitbucket.org/pypy/pypy/changeset/f94114913cc0/ Log: fix more tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -64,9 +64,9 @@ i8 = int_lt(i5, i7) guard_true(i8, descr=...) guard_not_invalidated(descr=...) - p10 = call(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) + p10 = call_r(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) guard_no_exception(descr=...) - i12 = call(ConstClass(ll_strhash), p10, descr=) + i12 = call_i(ConstClass(ll_strhash), p10, descr=) p13 = new(descr=...) p15 = new_array_clear(16, descr=) {{{ @@ -74,7 +74,7 @@ setfield_gc(p13, p15, descr=) setfield_gc(p13, ConstPtr(0), descr=) }}} - i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) + i17 = call_i(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) {{{ setfield_gc(p13, 0, descr=) setfield_gc(p13, 0, descr=) @@ -82,17 +82,17 @@ }}} guard_no_exception(descr=...) p20 = new_with_vtable(ConstClass(W_IntObject)) - call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) + call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) setfield_gc(p20, i5, descr=) guard_no_exception(descr=...) - i23 = call(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) + i23 = call_i(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) guard_no_exception(descr=...) i27 = int_lt(i23, 0) guard_false(i27, descr=...) - p28 = getfield_gc(p13, descr=) - p29 = getinteriorfield_gc(p28, i23, descr=>) + p28 = getfield_gc_r(p13, descr=) + p29 = getinteriorfield_gc_r(p28, i23, descr=>) guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...) - i31 = getfield_gc_pure(p29, descr=) + i31 = getfield_gc_pure_i(p29, descr=) i32 = int_sub_ovf(i31, i5) guard_no_overflow(descr=...) i34 = int_add_ovf(i32, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py --- a/pypy/module/pypyjit/test_pypy_c/test_globals.py +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -16,9 +16,9 @@ assert log.result == 500 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id("loadglobal", """ - p12 = getfield_gc(p10, descr=) + p12 = getfield_gc_r(p10, descr=) guard_value(p12, ConstPtr(ptr13), descr=...) guard_not_invalidated(descr=...) - p19 = getfield_gc(ConstPtr(p17), descr=) + p19 = getfield_gc_r(ConstPtr(p17), descr=) guard_value(p19, ConstPtr(ptr20), descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -106,7 +106,7 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc'] + 'getfield_gc_i'] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] # @@ -154,8 +154,8 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class', - 'getfield_gc', 'guard_value', # type check on the attribute + 'getfield_gc_r', 'guard_nonnull_class', + 'getfield_gc_r', 'guard_value', # type check on the attribute ] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] @@ -209,11 +209,11 @@ assert loop.match_by_id('loadattr1', ''' guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i19 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i22 = int_lt(i19, 0) guard_true(i22, descr=...) - i26 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i26 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i29 = int_lt(i26, 0) guard_true(i29, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -23,8 +23,8 @@ f1 = cast_int_to_float(i0) i3 = float_le(f1, 0.0) guard_false(i3, descr=...) - f2 = call(ConstClass(log), f1, descr=) - f3 = call(ConstClass(log10), f1, descr=) + f2 = call_f(ConstClass(log), f1, descr=) + f3 = call_f(ConstClass(log10), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i4 = int_add(i0, 1) @@ -52,8 +52,8 @@ f1 = cast_int_to_float(i0) i6 = --ISINF--(f1) guard_false(i6, descr=...) - f2 = call(ConstClass(sin), f1, descr=) - f3 = call(ConstClass(cos), f1, descr=) + f2 = call_f(ConstClass(sin), f1, descr=) + f3 = call_f(ConstClass(cos), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i7 = int_add(i0, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -15,36 +15,36 @@ loop = log._filter(log.loops[0]) assert loop.match(""" guard_class(p1, #, descr=...) - p4 = getfield_gc_pure(p1, descr=) - i5 = getfield_gc(p0, descr=) - p6 = getfield_gc_pure(p4, descr=) - p7 = getfield_gc_pure(p6, descr=) + p4 = getfield_gc_pure_r(p1, descr=) + i5 = getfield_gc_i(p0, descr=) + p6 = getfield_gc_pure_r(p4, descr=) + p7 = getfield_gc_pure_r(p6, descr=) guard_class(p7, ConstClass(Float64), descr=...) - i9 = getfield_gc_pure(p4, descr=) - i10 = getfield_gc_pure(p6, descr=) + i9 = getfield_gc_pure_i(p4, descr=) + i10 = getfield_gc_pure_i(p6, descr=) i12 = int_eq(i10, 61) i14 = int_eq(i10, 60) i15 = int_or(i12, i14) - f16 = raw_load(i9, i5, descr=) + f16 = raw_load_f(i9, i5, descr=) guard_true(i15, descr=...) guard_not_invalidated(descr=...) i18 = float_ne(f16, 0.000000) guard_true(i18, descr=...) guard_nonnull_class(p2, ConstClass(W_BoolBox), descr=...) - i20 = getfield_gc_pure(p2, descr=) + i20 = getfield_gc_pure_i(p2, descr=) i21 = int_is_true(i20) guard_false(i21, descr=...) - i22 = getfield_gc(p0, descr=) - i23 = getfield_gc_pure(p1, descr=) + i22 = getfield_gc_i(p0, descr=) + i23 = getfield_gc_pure_i(p1, descr=) guard_true(i23, descr=...) i25 = int_add(i22, 1) - p26 = getfield_gc_pure(p0, descr=) - i27 = getfield_gc_pure(p1, descr=) + p26 = getfield_gc_pure_r(p0, descr=) + i27 = getfield_gc_pure_i(p1, descr=) i28 = int_is_true(i27) guard_true(i28, descr=...) - i29 = getfield_gc_pure(p6, descr=) + i29 = getfield_gc_pure_i(p6, descr=) i30 = int_add(i5, i29) - i31 = getfield_gc_pure(p1, descr=) + i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) p34 = new_with_vtable(#) @@ -68,13 +68,13 @@ assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - f31 = raw_load(i9, i29, descr=) + f31 = raw_load_f(i9, i29, descr=) guard_not_invalidated(descr=...) i32 = float_ne(f31, 0.000000) guard_true(i32, descr=...) - i34 = getarrayitem_raw(#, #, descr=) # XXX what are these? + i34 = getarrayitem_raw_i(#, #, descr=) # XXX what are these? guard_value(i34, #, descr=...) # XXX don't appear in - i35 = getarrayitem_raw(#, #, descr=) # XXX equiv test_zjit + i35 = getarrayitem_raw_i(#, #, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, i28) i38 = int_ge(i36, i30) @@ -112,7 +112,7 @@ i78 = int_mul(i71, i61) i79 = int_add(i55, i78) """ + alignment_check + """ - f80 = raw_load(i67, i79, descr=) + f80 = raw_load_f(i67, i79, descr=) i81 = int_add(i71, 1) --TICK-- jump(..., descr=...) @@ -149,7 +149,7 @@ i83 = int_mul(i76, i64) i84 = int_add(i58, i83) """ + alignment_check + """ - f85 = raw_load(i70, i84, descr=) + f85 = raw_load_f(i70, i84, descr=) guard_not_invalidated(descr=...) f86 = float_add(f74, f85) i87 = int_add(i76, 1) @@ -176,7 +176,7 @@ guard_not_invalidated(descr=...) i88 = int_ge(i87, i59) guard_false(i88, descr=...) - f90 = raw_load(i67, i89, descr=) + f90 = raw_load_f(i67, i89, descr=) i91 = int_add(i87, 1) i93 = int_add(i89, i76) i94 = int_add(i79, 1) @@ -208,11 +208,11 @@ guard_true(i126, descr=...) i128 = int_mul(i117, i59) i129 = int_add(i55, i128) - f149 = raw_load(i100, i129, descr=) + f149 = raw_load_f(i100, i129, descr=) i151 = int_add(i117, 1) + setfield_gc(p156, i55, descr=) setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) - setfield_gc(p156, i55, descr=) --TICK-- jump(..., descr=...) """) @@ -241,9 +241,9 @@ raw_store(i103, i132, 42.000000, descr=) i153 = int_add(i120, 1) i154 = getfield_raw_i(#, descr=) + setfield_gc(p158, i53, descr=) setarrayitem_gc(p152, 1, 0, descr=) setarrayitem_gc(p152, 0, 0, descr=) - setfield_gc(p158, i53, descr=) i157 = int_lt(i154, 0) guard_false(i157, descr=...) jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -260,20 +260,18 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" guard_not_invalidated? - i14 = getfield_gc(p12, descr=) i16 = uint_ge(i12, i14) guard_false(i16, descr=...) - p16 = getfield_gc(p12, descr=) - p17 = getarrayitem_gc(p16, i12, descr=) + p17 = getarrayitem_gc_r(p16, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) guard_not_invalidated? - i21 = getfield_gc(p17, descr=) + i21 = getfield_gc_i(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) - i24 = getfield_gc(p17, descr=) - i25 = getarrayitem_raw(i24, 0, descr=<.*>) + i24 = getfield_gc_i(p17, descr=) + i25 = getarrayitem_raw_i(i24, 0, descr=<.*>) i27 = int_lt(1, i21) guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -128,7 +128,7 @@ guard_no_exception(descr=...) i92 = getfield_gc_i(p86, descr=) i93 = int_add(i92, 1) - p94 = getfield_gc(p86, descr=) + p94 = getfield_gc_r(p86, descr=) strsetitem(p94, i92, 32) setfield_gc(p86, i93, descr=) call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) @@ -248,9 +248,9 @@ i50 = int_add(i47, 1) setfield_gc(p15, i50, descr=) guard_not_invalidated(descr=...) - p80 = call(ConstClass(ll_str__IntegerR_SignedConst_Signed), i47, descr=) + p80 = call_r(ConstClass(ll_str__IntegerR_SignedConst_Signed), i47, descr=) guard_no_exception(descr=...) - p53 = call(ConstClass(fast_str_decode_ascii), p80, descr=) + p53 = call_r(ConstClass(fast_str_decode_ascii), p80, descr=) guard_no_exception(descr=...) guard_nonnull(p53, descr=...) --TICK-- From noreply at buildbot.pypy.org Sat Sep 12 21:18:06 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 12 Sep 2015 21:18:06 +0200 (CEST) Subject: [pypy-commit] pypy default: fix more tests Message-ID: <20150912191806.76A3B1C137C@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79595:4ca3af2a5ea4 Date: 2015-09-12 22:18 +0300 http://bitbucket.org/pypy/pypy/changeset/4ca3af2a5ea4/ Log: fix more tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -43,9 +43,9 @@ # can't change ;) assert loop.match_by_id("getitem", """ ... - i26 = call(ConstClass(ll_call_lookup_function), p18, p6, i25, 0, descr=...) + i26 = call_i(ConstClass(ll_call_lookup_function), p18, p6, i25, 0, descr=...) ... - p33 = getinteriorfield_gc(p31, i26, descr=>) + p33 = getinteriorfield_gc_r(p31, i26, descr=>) ... """) 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 @@ -1085,7 +1085,7 @@ # we want to call the function that does the aroundstate # manipulation here (as a hack, instead of really doing # the aroundstate manipulation ourselves) - return self.execute_call_may_force(descr, func, *args) + return self._execute_call_may_force(descr, func, *args) guard_op = self.lltrace.operations[self.current_index + 1] assert guard_op.getopnum() == rop.GUARD_NOT_FORCED self.force_guard_op = guard_op From noreply at buildbot.pypy.org Sat Sep 12 21:35:15 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 12 Sep 2015 21:35:15 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Check in the talk from Remi and me at Zurich Message-ID: <20150912193515.D6AB41C137C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r5557:b29c02291a9f Date: 2015-09-12 21:36 +0200 http://bitbucket.org/pypy/extradoc/changeset/b29c02291a9f/ Log: Check in the talk from Remi and me at Zurich diff --git a/talk/vmm2015/VM Meetup 2015.pdf b/talk/vmm2015/VM Meetup 2015.pdf new file mode 100644 index 0000000000000000000000000000000000000000..364dd4564d16978567e299c35af780583b610bf6 GIT binary patch [cut] From noreply at buildbot.pypy.org Sat Sep 12 21:53:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 12 Sep 2015 21:53:24 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150912195324.E3B9F1C12D4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r634:f4deeac4f2e3 Date: 2015-09-12 21:54 +0200 http://bitbucket.org/pypy/pypy.org/changeset/f4deeac4f2e3/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -9,13 +9,13 @@ - $60026 of $105000 (57.2%) + $60284 of $105000 (57.4%)

    @@ -23,7 +23,7 @@
  • diff --git a/don3.html b/don3.html --- a/don3.html +++ b/don3.html @@ -9,13 +9,13 @@ - $52486 of $60000 (87.5%) + $52608 of $60000 (87.7%)
    @@ -23,7 +23,7 @@
  • diff --git a/don4.html b/don4.html --- a/don4.html +++ b/don4.html @@ -9,7 +9,7 @@ @@ -17,7 +17,7 @@ 2nd call: - $29248 of $80000 (36.6%) + $29320 of $80000 (36.7%)
    @@ -25,7 +25,7 @@
  • From noreply at buildbot.pypy.org Sun Sep 13 10:55:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 10:55:43 +0200 (CEST) Subject: [pypy-commit] pypy default: a test and a fix for numpy crash Message-ID: <20150913085543.AF3ED1C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79596:b4456aa540b3 Date: 2015-09-13 10:55 +0200 http://bitbucket.org/pypy/pypy/changeset/b4456aa540b3/ Log: a test and a fix for numpy crash 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 @@ -782,5 +782,11 @@ def __init__(self, const): self._const = const + def is_constant(self): + return True + + def getconst(self): + return self._const + def make_guards(self, op, short, optimizer): short.append(ResOperation(rop.GUARD_VALUE, [op, self._const])) 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 @@ -8827,5 +8827,21 @@ """ self.optimize_loop(ops, expected) + def test_virtual_with_floats(self): + ops = """ + [p1, i1] + p0 = new_with_vtable(descr=nodesize) + i2 = int_add(i1, 1) + setfield_gc(p0, 0.0000, descr=floatdescr) + setfield_gc(p0, i2, descr=valuedescr) + jump(p0, i2) + """ + expected = """ + [i1] + i2 = int_add(i1, 1) + jump(i2) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py @@ -378,6 +378,10 @@ if info.upper > MAXINT / 2: info.upper = MAXINT self.intbound = info + elif type == 'f': + if info and info.is_constant(): + self.level = LEVEL_CONSTANT + self.constbox = info.getconst() def is_const(self): return self.constbox is not None From noreply at buildbot.pypy.org Sun Sep 13 11:30:15 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 11:30:15 +0200 (CEST) Subject: [pypy-commit] pypy default: a test and a fix Message-ID: <20150913093015.14EE61C0748@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79597:75a3c9bce078 Date: 2015-09-13 11:30 +0200 http://bitbucket.org/pypy/pypy/changeset/75a3c9bce078/ Log: a test and a fix 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 @@ -8843,5 +8843,43 @@ """ self.optimize_loop(ops, expected) + def test_same_as_preserves_info_in_the_preamble(self): + ops = """ + [p0, p1, i1] + i2 = int_add(i1, 1) + setfield_gc(p0, i2, descr=valuedescr) + i = int_le(i2, 13) + guard_true(i) [] + if00 = getfield_gc_i(p0, descr=valuedescr) + icheck = int_le(if00, 13) + guard_true(icheck) [] + jump(p0, p1, i1) + """ + expected = """ + [p0, p1, i1, i2] + setfield_gc(p0, i2, descr=valuedescr) + jump(p0, p1, i1, i2) + """ + self.optimize_loop(ops, expected) + + def test_same_as_preserves_info_in_the_preamble_2(self): + ops = """ + [i0, p0] + ifoo = getfield_gc_i(p0, descr=valuedescr) + icheck = int_lt(ifoo, 13) + guard_true(icheck) [] + i1 = int_add(i0, 1) + i2 = int_lt(i1, 13) + guard_true(i2) [] + setfield_gc(p0, i1, descr=valuedescr) + jump(i0, p0) + """ + expected = """ + [i0, p0, i4] + setfield_gc(p0, i4, descr=valuedescr) + jump(i0, p0, i4) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -10,7 +10,8 @@ from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo from rpython.jit.metainterp.optimizeopt.virtualstate import ( VirtualStateConstructor, VirtualStatesCantMatch) -from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp +from rpython.jit.metainterp.resoperation import rop, ResOperation, GuardResOp,\ + AbstractResOp from rpython.jit.metainterp import compile from rpython.rlib.debug import debug_print, debug_start, debug_stop,\ have_debug_prints @@ -359,7 +360,10 @@ op.set_forwarded(None) def _expand_info(self, arg, infos): - info = self.optimizer.getinfo(arg) + if isinstance(arg, AbstractResOp) and arg.is_same_as(): + info = self.optimizer.getinfo(arg.getarg(0)) + else: + info = self.optimizer.getinfo(arg) if arg in infos: return if info: @@ -395,7 +399,7 @@ for produced_op in short_boxes: op = produced_op.short_op.res if not isinstance(op, Const): - infos[op] = self.optimizer.getinfo(op) + self._expand_info(op, infos) self.optimizer._clean_optimization_info(end_args) self.optimizer._clean_optimization_info(start_label.getarglist()) return ExportedState(label_args, end_args, virtual_state, infos, From noreply at buildbot.pypy.org Sun Sep 13 11:51:53 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 11:51:53 +0200 (CEST) Subject: [pypy-commit] pypy default: oops Message-ID: <20150913095153.7BDB71C0748@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79598:c251644bdb57 Date: 2015-09-13 11:52 +0200 http://bitbucket.org/pypy/pypy/changeset/c251644bdb57/ Log: oops diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py --- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py +++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py @@ -418,7 +418,7 @@ if isinstance(op, Const): info = optimizer.getinfo(op) else: - info = exported_infos[op] + info = exported_infos.get(op, None) if info is None: info = empty_info preamble_op.set_forwarded(info) From noreply at buildbot.pypy.org Sun Sep 13 12:22:21 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 12:22:21 +0200 (CEST) Subject: [pypy-commit] pypy default: fix some more tests Message-ID: <20150913102221.D82991C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79599:d9df217854da Date: 2015-09-13 12:22 +0200 http://bitbucket.org/pypy/pypy/changeset/d9df217854da/ Log: fix some more tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -81,7 +81,7 @@ setfield_gc(p13, 32, descr=) }}} guard_no_exception(descr=...) - p20 = new_with_vtable(ConstClass(W_IntObject)) + p20 = new_with_vtable(descr=...) call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) setfield_gc(p20, i5, descr=) guard_no_exception(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py --- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py +++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py @@ -31,7 +31,7 @@ # but all calls can be special-cased by the backend if # supported. On 64-bit there is only the two calls to # read_timestamp. - r = re.compile(r" call[(]ConstClass[(](.+?)[)]") + r = re.compile(r" call_\w[(]ConstClass[(](.+?)[)]") calls = r.findall(repr(loop.ops_by_id(method))) if sys.maxint == 2147483647: assert len(calls) == 6 diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -124,7 +124,7 @@ setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) - jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...) + jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, p100, descr=...) """) def test_mutate_class(self): @@ -167,7 +167,7 @@ i70 = int_lt(i58, i33) guard_true(i70, descr=...) guard_not_invalidated(descr=...) - p71 = getfield_gc(p64, descr=...) + p71 = getfield_gc_r(p64, descr=...) guard_value(p71, ConstPtr(ptr42), descr=...) p72 = force_token() p73 = force_token() @@ -175,7 +175,7 @@ i75 = getfield_raw_i(..., descr=...) i76 = int_lt(i75, 0) guard_false(i76, descr=...) - p77 = new_with_vtable(...) + p77 = new_with_vtable(descr=...) setfield_gc(p77, p64, descr=...) setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(null), descr=...) @@ -183,7 +183,7 @@ setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(ptr42), descr=...) setfield_gc(ConstPtr(ptr69), p77, descr=...) - jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...) + jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, p100, descr=...) """) From noreply at buildbot.pypy.org Sun Sep 13 12:37:41 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 12:37:41 +0200 (CEST) Subject: [pypy-commit] pypy default: fix 2 more tests Message-ID: <20150913103741.32B201C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79600:039928bbf710 Date: 2015-09-13 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/039928bbf710/ Log: fix 2 more tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -38,7 +38,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) loop2 = log.loops[0] @@ -50,11 +50,11 @@ guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) - p18 = getarrayitem_gc(p5, i11, descr=...) + p18 = getarrayitem_gc_r(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) - i20 = getfield_gc_pure(p18, descr=...) + i20 = getfield_gc_pure_i(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) @@ -79,6 +79,6 @@ assert len(guards) < 20 assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -65,7 +65,7 @@ assert loop.match(""" i7 = int_gt(i4, 1) guard_true(i7, descr=...) - p11 = call(ConstClass(rbigint.int_mul), p5, i4, descr=...) + p11 = call_r(ConstClass(rbigint.int_mul), p5, i4, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) --TICK-- @@ -113,14 +113,14 @@ i12 = int_is_true(i4) guard_true(i12, descr=...) guard_not_invalidated(descr=...) - i13 = int_add_ovf(i8, i9) - guard_no_overflow(descr=...) - i10p = getfield_gc_pure(p10, descr=...) + i10p = getfield_gc_pure_i(p10, descr=...) i10 = int_mul_ovf(2, i10p) guard_no_overflow(descr=...) i14 = int_add_ovf(i13, i10) guard_no_overflow(descr=...) - setfield_gc(p7, p11, descr=...) + i13 = int_add_ovf(i14, i9) + guard_no_overflow(descr=...) + setfield_gc(p17, p10, descr=...) i17 = int_sub_ovf(i4, 1) guard_no_overflow(descr=...) --TICK-- @@ -277,6 +277,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=...) --TICK-- + if00 = arraylen_gc(p16, descr=...) jump(..., descr=...) """) From noreply at buildbot.pypy.org Sun Sep 13 12:44:16 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 12:44:16 +0200 (CEST) Subject: [pypy-commit] pypy default: emitting does not seem to be ever set to False Message-ID: <20150913104416.3B7D61C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79601:ea4ca6dad408 Date: 2015-09-13 12:44 +0200 http://bitbucket.org/pypy/pypy/changeset/ea4ca6dad408/ Log: emitting does not seem to be ever set to False 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 @@ -257,8 +257,6 @@ self.optearlyforce = None self.optunroll = None - self._emitting = True - self.set_optimizations(optimizations) self.setup() @@ -580,9 +578,8 @@ self.force_box(farg) elif op.can_raise(): self.exception_might_have_happened = True - if self._emitting: - self._really_emitted_operation = op - self._newoperations.append(op) + self._really_emitted_operation = op + self._newoperations.append(op) def getlastop(self): return self._really_emitted_operation From noreply at buildbot.pypy.org Sun Sep 13 12:59:38 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 12:59:38 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: start branch for sharing guards Message-ID: <20150913105938.A0FBD1C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79602:00542277afd9 Date: 2015-09-13 12:59 +0200 http://bitbucket.org/pypy/pypy/changeset/00542277afd9/ Log: start branch for sharing guards 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 @@ -1,7 +1,6 @@ from rpython.jit.metainterp import jitprof, resume, compile from rpython.jit.metainterp.executor import execute_nonspec_const -from rpython.jit.metainterp.logger import LogOperations -from rpython.jit.metainterp.history import Const, ConstInt, REF, ConstPtr +from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\ ConstIntBound, MININT, MAXINT from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method @@ -258,6 +257,7 @@ self.optunroll = None self._emitting = True + self._last_guard_op = None self.set_optimizations(optimizations) self.setup() @@ -573,17 +573,34 @@ return else: guard_op = self.replace_op_with(op, op.getopnum()) - op = self.store_final_boxes_in_guard(guard_op, pendingfields) - # for unrolling - for farg in op.getfailargs(): - if farg: - self.force_box(farg) + if self._last_guard_op: + op = self._copy_resume_data_from(guard_op, + self._last_guard_op) + else: + op = self.store_final_boxes_in_guard(guard_op, + pendingfields) + self._last_guard_op = op + # for unrolling + for farg in op.getfailargs(): + if farg: + self.force_box(farg) elif op.can_raise(): self.exception_might_have_happened = True if self._emitting: + if op.has_no_side_effect() or op.is_guard(): + pass + else: + self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) + def _copy_resume_data_from(self, guard_op, last_guard_op): + descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) + descr.copy_all_attributes_from(last_guard_op.getdescr()) + guard_op.setdescr(descr) + guard_op.setfailargs(last_guard_op.getfailargs()) + return guard_op + def getlastop(self): return self._really_emitted_operation From noreply at buildbot.pypy.org Sun Sep 13 13:31:48 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 13:31:48 +0200 (CEST) Subject: [pypy-commit] pypy default: a bit blindly fix windows test Message-ID: <20150913113148.D66371C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79603:0446b26c5c6b Date: 2015-09-13 13:32 +0200 http://bitbucket.org/pypy/pypy/changeset/0446b26c5c6b/ Log: a bit blindly fix windows test diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2601,16 +2601,16 @@ # call: 8 bytes too much. If we repeat the call often enough, crash. ops = [] for i in range(50): - i3 = InputArgInt() ops += [ - ResOperation(rop.CALL_RELEASE_GIL, - [ConstInt(0), funcbox, i1, i2], i3, + ResOperation(rop.CALL_RELEASE_GIL_N, + [ConstInt(0), funcbox, i1, i2], descr=calldescr), ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), ] + i3 = ops[-2] ops[-1].setfailargs([]) ops += [ - ResOperation(rop.FINISH, [i3], None, descr=BasicFinalDescr(0)) + ResOperation(rop.FINISH, [i3], descr=BasicFinalDescr(0)) ] looptoken = JitCellToken() self.cpu.compile_loop([i1, i2], ops, looptoken) From noreply at buildbot.pypy.org Sun Sep 13 13:36:27 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 13:36:27 +0200 (CEST) Subject: [pypy-commit] pypy default: kill unused function Message-ID: <20150913113628.007D61C0748@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79604:bfa159c0c21a Date: 2015-09-13 13:36 +0200 http://bitbucket.org/pypy/pypy/changeset/bfa159c0c21a/ Log: kill unused function diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -434,18 +434,6 @@ return label_args - def is_call_pure_with_exception(self, op): - if op.is_call_pure(): - effectinfo = op.getdescr().get_extra_info() - # Assert that only EF_ELIDABLE_CANNOT_RAISE or - # EF_ELIDABLE_OR_MEMORYERROR end up here, not - # for example EF_ELIDABLE_CAN_RAISE. - assert effectinfo.extraeffect in ( - effectinfo.EF_ELIDABLE_CANNOT_RAISE, - effectinfo.EF_ELIDABLE_OR_MEMORYERROR) - return effectinfo.extraeffect != effectinfo.EF_ELIDABLE_CANNOT_RAISE - return False - class UnrollInfo(LoopInfo): """ A state after optimizing the peeled loop, contains the following: From noreply at buildbot.pypy.org Sun Sep 13 13:59:22 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 13 Sep 2015 13:59:22 +0200 (CEST) Subject: [pypy-commit] pypy default: fix more test(s) Message-ID: <20150913115922.6F7611C0748@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79605:63de0ec77acd Date: 2015-09-13 14:59 +0300 http://bitbucket.org/pypy/pypy/changeset/63de0ec77acd/ Log: fix more test(s) diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py --- a/pypy/module/_rawffi/array.py +++ b/pypy/module/_rawffi/array.py @@ -89,6 +89,7 @@ # function call, ffi_call() writes 8 bytes into it even if the # function's result type asks for less. memsize = clibffi.adjust_return_size(memsize) + import pdb;pdb.set_trace() W_DataInstance.__init__(self, space, memsize, address) self.length = length self.shape = shape diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2602,10 +2602,10 @@ ops = [] for i in range(50): ops += [ - ResOperation(rop.CALL_RELEASE_GIL_N, + ResOperation(rop.CALL_RELEASE_GIL_I, [ConstInt(0), funcbox, i1, i2], descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] i3 = ops[-2] ops[-1].setfailargs([]) From noreply at buildbot.pypy.org Sun Sep 13 14:02:16 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 13 Sep 2015 14:02:16 +0200 (CEST) Subject: [pypy-commit] pypy default: whoops Message-ID: <20150913120216.A8ED51C0748@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79606:13eb1145d947 Date: 2015-09-13 15:02 +0300 http://bitbucket.org/pypy/pypy/changeset/13eb1145d947/ Log: whoops diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py --- a/pypy/module/_rawffi/array.py +++ b/pypy/module/_rawffi/array.py @@ -89,7 +89,6 @@ # function call, ffi_call() writes 8 bytes into it even if the # function's result type asks for less. memsize = clibffi.adjust_return_size(memsize) - import pdb;pdb.set_trace() W_DataInstance.__init__(self, space, memsize, address) self.length = length self.shape = shape From noreply at buildbot.pypy.org Sun Sep 13 15:35:43 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 13 Sep 2015 15:35:43 +0200 (CEST) Subject: [pypy-commit] pypy default: try to fix more tests, still fail on backend/x86/ test_call_to* Message-ID: <20150913133543.70D5F1C02C5@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79607:c20b3d2b2276 Date: 2015-09-13 16:35 +0300 http://bitbucket.org/pypy/pypy/changeset/c20b3d2b2276/ Log: try to fix more tests, still fail on backend/x86/ test_call_to* diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -3072,16 +3072,16 @@ rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_ALT_ERRNO, ]: faildescr = BasicFailDescr(1) - inputargs = [BoxInt() for i in range(7)] - i1 = BoxInt() + inputargs = [InputArgInt() for i in range(7)] ops = [ - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [ConstInt(saveerr), ConstInt(func1_adr)] - + inputargs, i1, + + inputargs, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), - ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0)) + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] + i1 = ops[0] + ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))] ops[-2].setfailargs([]) looptoken = JitCellToken() self.cpu.compile_loop(inputargs, ops, looptoken) @@ -3142,16 +3142,16 @@ rffi.RFFI_READSAVED_LASTERROR | rffi.RFFI_ALT_ERRNO, ]: faildescr = BasicFailDescr(1) - inputargs = [BoxInt() for i in range(7)] - i1 = BoxInt() + inputargs = [InputArgInt() for i in range(7)] ops = [ - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [ConstInt(saveerr), ConstInt(func1_adr)] - + inputargs, i1, + + inputargs, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), - ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0)) + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] + i1 = ops[-2] + ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))] ops[-2].setfailargs([]) looptoken = JitCellToken() self.cpu.compile_loop(inputargs, ops, looptoken) From noreply at buildbot.pypy.org Sun Sep 13 17:12:50 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 17:12:50 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: whack a bit until we can share more Message-ID: <20150913151250.2DD961C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79608:986e925ea183 Date: 2015-09-13 17:12 +0200 http://bitbucket.org/pypy/pypy/changeset/986e925ea183/ Log: whack a bit until we can share more diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py --- a/rpython/jit/codewriter/flatten.py +++ b/rpython/jit/codewriter/flatten.py @@ -216,24 +216,21 @@ if linkfalse.llexitcase == True: linkfalse, linktrue = linktrue, linkfalse opname = 'goto_if_not' - livebefore = False if isinstance(block.exitswitch, tuple): # special case produced by jtransform.optimize_goto_if_not() opname = 'goto_if_not_' + block.exitswitch[0] opargs = block.exitswitch[1:] if opargs[-1] == '-live-before': - livebefore = True opargs = opargs[:-1] else: assert block.exitswitch.concretetype == lltype.Bool opargs = [block.exitswitch] # lst = self.flatten_list(opargs) + [TLabel(linkfalse)] - if livebefore: - self.emitline('-live-') + self.emitline('-live-') self.emitline(opname, *lst) - if not livebefore: - self.emitline('-live-', TLabel(linkfalse)) + #if not livebefore: + # self.emitline('-live-', TLabel(linkfalse)) # true path: self.make_link(linktrue) # false path: 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 @@ -211,8 +211,8 @@ # ok! optimize this case block.operations.remove(op) block.exitswitch = (op.opname,) + tuple(op.args) - if op.opname in ('ptr_iszero', 'ptr_nonzero'): - block.exitswitch += ('-live-before',) + #if op.opname in ('ptr_iszero', 'ptr_nonzero'): + block.exitswitch += ('-live-before',) # if the variable escape to the next block along a link, # replace it with a constant, because we know its value for link in block.exits: 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 @@ -1473,7 +1473,7 @@ elif opnum == rop.GUARD_TRUE: # Produced directly by some goto_if_not_xxx() opcode that did not # jump, but which must now jump. The pc is just after the opcode. - self.position = self.jitcode.follow_jump(self.position) + pass # self.position = self.jitcode.follow_jump(self.position) # elif opnum == rop.GUARD_FALSE: # Produced directly by some goto_if_not_xxx() opcode that jumped, 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 @@ -599,6 +599,8 @@ descr.copy_all_attributes_from(last_guard_op.getdescr()) guard_op.setdescr(descr) guard_op.setfailargs(last_guard_op.getfailargs()) + if guard_op.getopnum() == rop.GUARD_VALUE: + guard_op = self._maybe_replace_guard_value(guard_op, descr) return guard_op def getlastop(self): @@ -641,24 +643,28 @@ descr.store_final_boxes(op, newboxes, self.metainterp_sd) # if op.getopnum() == rop.GUARD_VALUE: - if op.getarg(0).type == 'i': - b = self.getintbound(op.getarg(0)) - if b.is_bool(): - # Hack: turn guard_value(bool) into guard_true/guard_false. - # This is done after the operation is emitted to let - # store_final_boxes_in_guard set the guard_opnum field of - # the descr to the original rop.GUARD_VALUE. - constvalue = op.getarg(1).getint() - if constvalue == 0: - opnum = rop.GUARD_FALSE - elif constvalue == 1: - opnum = rop.GUARD_TRUE - else: - raise AssertionError("uh?") - newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr) - return newop - # a real GUARD_VALUE. Make it use one counter per value. - descr.make_a_counter_per_value(op) + op = self._maybe_replace_guard_value(op, descr) + return op + + def _maybe_replace_guard_value(self, op, descr): + if op.getarg(0).type == 'i': + b = self.getintbound(op.getarg(0)) + if b.is_bool(): + # Hack: turn guard_value(bool) into guard_true/guard_false. + # This is done after the operation is emitted to let + # store_final_boxes_in_guard set the guard_opnum field of + # the descr to the original rop.GUARD_VALUE. + constvalue = op.getarg(1).getint() + if constvalue == 0: + opnum = rop.GUARD_FALSE + elif constvalue == 1: + opnum = rop.GUARD_TRUE + else: + raise AssertionError("uh?") + newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr) + return newop + # a real GUARD_VALUE. Make it use one counter per value. + descr.make_a_counter_per_value(op) return op def optimize_default(self, op): 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 @@ -329,37 +329,37 @@ def opimpl_goto(self, target): self.pc = target - @arguments("box", "label") - def opimpl_goto_if_not(self, box, target): + @arguments("box", "label", "orgpc") + def opimpl_goto_if_not(self, box, target, orgpc): switchcase = box.getint() if switchcase: opnum = rop.GUARD_TRUE else: opnum = rop.GUARD_FALSE - self.metainterp.generate_guard(opnum, box) + self.metainterp.generate_guard(opnum, box, resumepc=orgpc) if not switchcase: self.pc = target - @arguments("box", "label") - def opimpl_goto_if_not_int_is_true(self, box, target): + @arguments("box", "label", "orgpc") + def opimpl_goto_if_not_int_is_true(self, box, target, orgpc): condbox = self.execute(rop.INT_IS_TRUE, box) - self.opimpl_goto_if_not(condbox, target) + self.opimpl_goto_if_not(condbox, target, orgpc) - @arguments("box", "label") - def opimpl_goto_if_not_int_is_zero(self, box, target): + @arguments("box", "label", "orgpc") + def opimpl_goto_if_not_int_is_zero(self, box, target, orgpc): condbox = self.execute(rop.INT_IS_ZERO, box) - self.opimpl_goto_if_not(condbox, target) + self.opimpl_goto_if_not(condbox, target, orgpc) for _opimpl in ['int_lt', 'int_le', 'int_eq', 'int_ne', 'int_gt', 'int_ge', 'ptr_eq', 'ptr_ne']: exec py.code.Source(''' - @arguments("box", "box", "label") - def opimpl_goto_if_not_%s(self, b1, b2, target): + @arguments("box", "box", "label", "orgpc") + def opimpl_goto_if_not_%s(self, b1, b2, target, orgpc): if b1 is b2: condbox = %s else: condbox = self.execute(rop.%s, b1, b2) - self.opimpl_goto_if_not(condbox, target) + self.opimpl_goto_if_not(condbox, target, orgpc) ''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper()) ).compile() @@ -2456,7 +2456,7 @@ if opnum == rop.GUARD_FUTURE_CONDITION: pass elif opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now - frame.pc = frame.jitcode.follow_jump(frame.pc) + pass # frame.pc = frame.jitcode.follow_jump(frame.pc) elif opnum == rop.GUARD_FALSE: # a goto_if_not that stops jumping; pass # or a switch that was in its "default" case elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS: From noreply at buildbot.pypy.org Sun Sep 13 17:48:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 17:48:20 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: improve the situation Message-ID: <20150913154820.536511C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79609:30e029463a07 Date: 2015-09-13 17:48 +0200 http://bitbucket.org/pypy/pypy/changeset/30e029463a07/ Log: improve the situation 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 @@ -587,7 +587,7 @@ elif op.can_raise(): self.exception_might_have_happened = True if self._emitting: - if op.has_no_side_effect() or op.is_guard(): + if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): pass else: self._last_guard_op = None diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -236,6 +236,9 @@ return (self.getopnum() == rop.GUARD_OVERFLOW or self.getopnum() == rop.GUARD_NO_OVERFLOW) + def is_jit_debug(self): + return rop._JIT_DEBUG_FIRST <= self.getopnim() <= rop._JIT_DEBUG_LAST + def is_always_pure(self): return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST @@ -804,10 +807,12 @@ 'UNICODESETITEM/3/n', 'COND_CALL_GC_WB/1d/n', # [objptr] (for the write barrier) 'COND_CALL_GC_WB_ARRAY/2d/n', # [objptr, arrayindex] (write barr. for array) + '_JIT_DEBUG_FIRST', 'DEBUG_MERGE_POINT/*/n', # debugging only 'ENTER_PORTAL_FRAME/2/n', # debugging only 'LEAVE_PORTAL_FRAME/1/n', # debugging only 'JIT_DEBUG/*/n', # debugging only + '_JIT_DEBUG_LAST', 'VIRTUAL_REF_FINISH/2/n', # removed before it's passed to the backend 'COPYSTRCONTENT/5/n', # src, dst, srcstart, dststart, length 'COPYUNICODECONTENT/5/n', 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 @@ -230,8 +230,8 @@ res = self.meta_interp(f, [6, 32, 16]) assert res == 1692 self.check_trace_count(3) - self.check_resops({'int_lt': 2, 'int_gt': 4, 'guard_false': 2, - 'guard_true': 4, 'int_sub': 4, 'jump': 3, + self.check_resops({'int_lt': 4, 'int_gt': 4, 'guard_false': 2, + 'guard_true': 6, 'int_sub': 4, 'jump': 3, 'int_mul': 3, 'int_add': 4}) def test_loop_invariant_mul_ovf2(self): From noreply at buildbot.pypy.org Sun Sep 13 17:55:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 13 Sep 2015 17:55:54 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: typo Message-ID: <20150913155554.17E241C02C5@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79610:895479ea3d61 Date: 2015-09-13 17:56 +0200 http://bitbucket.org/pypy/pypy/changeset/895479ea3d61/ Log: typo diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -237,7 +237,7 @@ self.getopnum() == rop.GUARD_NO_OVERFLOW) def is_jit_debug(self): - return rop._JIT_DEBUG_FIRST <= self.getopnim() <= rop._JIT_DEBUG_LAST + return rop._JIT_DEBUG_FIRST <= self.getopnum() <= rop._JIT_DEBUG_LAST def is_always_pure(self): return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST From noreply at buildbot.pypy.org Mon Sep 14 10:28:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 10:28:20 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: access JitCell from the interpreter Message-ID: <20150914082820.27DE91C1DCE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79611:60a87ed91e06 Date: 2015-09-14 10:26 +0200 http://bitbucket.org/pypy/pypy/changeset/60a87ed91e06/ Log: access JitCell from the interpreter diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -156,6 +156,20 @@ assert jit_hooks.stats_get_times_value(None, Counters.TRACING) == 0 self.meta_interp(main, [], ProfilerClass=EmptyProfiler) + def test_get_jitcell_at_key(self): + driver = JitDriver(greens = ['s'], reds = ['i'], name='jit') + + def loop(i, s): + while i > s: + driver.jit_merge_point(i=i, s=s) + i -= 1 + + def main(s): + loop(30, s) + assert jit_hooks.get_jitcell_at_key("jit", s) + assert not jit_hooks.get_jitcell_at_key("jit", s + 1) + + self.meta_interp(main, [5]) class LLJitHookInterfaceTests(JitHookInterfaceTests): # use this for any backend, instead of the super class diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -1,9 +1,9 @@ -import sys +import sys, py from rpython.tool.sourcetools import func_with_new_name from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.annlowlevel import (llhelper, MixLevelHelperAnnotator, - cast_base_ptr_to_instance, hlstr) + cast_base_ptr_to_instance, hlstr, cast_instance_to_gcref) from rpython.rtyper.llannotation import lltype_to_annotation from rpython.annotator import model as annmodel from rpython.rtyper.llinterp import LLException @@ -236,6 +236,7 @@ self.rewrite_can_enter_jits() self.rewrite_set_param_and_get_stats() self.rewrite_force_virtual(vrefinfo) + self.rewrite_jitcell_accesses() self.rewrite_force_quasi_immutable() self.add_finish() self.metainterp_sd.finish_setup(self.codewriter) @@ -598,6 +599,45 @@ (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE) + def rewrite_jitcell_accesses(self): + jitdrivers_by_name = {} + for jd in self.jitdrivers_sd: + name = jd.jitdriver.name + if name != 'jitdriver': + jitdrivers_by_name[name] = jd + m = _find_jit_marker(self.translator.graphs, 'get_jitcell_at_key', + False) + accessors = {} + + def get_accessor(jitdriver_name, function, ARGS): + a = accessors.get(jitdriver_name) + if a: + return a + d = {'function': function, + 'cast_instance_to_gcref': cast_instance_to_gcref} + arg_spec = ", ".join([("arg%d" % i) for i in range(len(ARGS))]) + exec py.code.Source(""" + def accessor(%s): + return cast_instance_to_gcref(function(%s)) + """ % (arg_spec, arg_spec)).compile() in d + FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) + ll_ptr = self.helper_func(FUNC, d['accessor']) + accessors[jitdriver_name] = ll_ptr + return ll_ptr + + for graph, block, index in m: + op = block.operations[index] + jitdriver_name = op.args[1].value + JitCell = jitdrivers_by_name[jitdriver_name].warmstate.JitCell + ARGS = [x.concretetype for x in op.args[2:]] + accessor = get_accessor(jitdriver_name, JitCell.get_jitcell, + ARGS) + v_result = op.result + c_accessor = Constant(accessor, concretetype=lltype.Void) + newop = SpaceOperation('direct_call', [c_accessor] + op.args[2:], + v_result) + block.operations[index] = newop + def rewrite_can_enter_jits(self): sublists = {} for jd in self.jitdrivers_sd: diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -5,6 +5,7 @@ cast_base_ptr_to_instance, llstr) from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rtyper.lltypesystem import llmemory, lltype +from rpython.flowspace.model import Constant from rpython.rtyper import rclass @@ -127,3 +128,24 @@ @register_helper(lltype.Ptr(LOOP_RUN_CONTAINER)) def stats_get_loop_run_times(warmrunnerdesc): return warmrunnerdesc.metainterp_sd.cpu.get_all_loop_runs() + +# ---------------------- jitcell interface ---------------------- + +def get_jitcell_at_key(name, *greenkey): + raise Exception("need to run translated") + +class GetJitCellEntry(ExtRegistryEntry): + _about_ = get_jitcell_at_key + + def compute_result_annotation(self, s_name, *args_s): + assert s_name.is_constant() + return SomePtr(llmemory.GCREF) + + def specialize_call(self, hop): + c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) + c_name = Constant("get_jitcell_at_key", concretetype=lltype.Void) + hop.exception_cannot_occur() + args_v = [hop.inputarg(arg, arg=i + 1) + for i, arg in enumerate(hop.args_r[1:])] + return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, + resulttype=hop.r_result) From noreply at buildbot.pypy.org Mon Sep 14 10:44:15 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Mon, 14 Sep 2015 10:44:15 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: update TODO Message-ID: <20150914084415.CE1B81C0748@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79612:f7db687c6f7b Date: 2015-09-14 10:48 +0200 http://bitbucket.org/pypy/pypy/changeset/f7db687c6f7b/ Log: update TODO diff --git a/TODO b/TODO --- a/TODO +++ b/TODO @@ -1,15 +1,3 @@ ------------------------------------------------------------- - -## maybe resolved: -also a possible cause for the thing below this one: - pypy-stm frees 530936 loop tokens - pypy26 frees 446 loop tokens -meaning, loops get freed and probably must be retraced all -the time... see XXXXXX in memmgr.py - -one problem was wrong counting, so now its 1551 vs. 446. Still -probably too much. - ------------------------------------------------------------ annotating and rtyping pixie with --jit=off and 1 thread (no @@ -17,6 +5,10 @@ STM: 148s pypy2.6: 91.3s +full mapdict and methodcache bring STM down to 130s, which +is a reasonable 40% overhead. --> think about fixing mapdict +and methodcache with STM + This difference may also explain a similar with-jit result: STM: 96 pypy2.6: 64.5s @@ -25,8 +17,8 @@ pypy2.6: 64s (still using only 1 thread) TODOs: -1) stmdict/stmset need strategies -2) methodcache missing or generally no-jit performance is bad here +1) stmdict/stmset need strategies (only ~2% perf here) +2) methodcache & mapdict for generally better no-jit performance 3) theoretically, more threads shouldn't take even longer ------------------------------------------------------------ From noreply at buildbot.pypy.org Mon Sep 14 10:49:55 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 10:49:55 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: implement trace at next iteration Message-ID: <20150914084955.76C731C0748@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79613:6e6ac7561485 Date: 2015-09-14 10:50 +0200 http://bitbucket.org/pypy/pypy/changeset/6e6ac7561485/ Log: implement trace at next iteration diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -168,8 +168,12 @@ loop(30, s) assert jit_hooks.get_jitcell_at_key("jit", s) assert not jit_hooks.get_jitcell_at_key("jit", s + 1) + jit_hooks.trace_next_iteration("jit", s + 1) + loop(s + 3, s + 1) + assert jit_hooks.get_jitcell_at_key("jit", s + 1) self.meta_interp(main, [5]) + self.check_jitcell_token_count(2) class LLJitHookInterfaceTests(JitHookInterfaceTests): # use this for any backend, instead of the super class diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -129,6 +129,17 @@ results.append((graph, block, i)) return results +def _find_jit_markers(graphs, marker_names): + results = [] + for graph in graphs: + for block in graph.iterblocks(): + for i in range(len(block.operations)): + op = block.operations[i] + if (op.opname == 'jit_marker' and + op.args[0].value in marker_names): + results.append((graph, block, i)) + return results + def find_can_enter_jit(graphs): return _find_jit_marker(graphs, 'can_enter_jit') @@ -605,12 +616,12 @@ name = jd.jitdriver.name if name != 'jitdriver': jitdrivers_by_name[name] = jd - m = _find_jit_marker(self.translator.graphs, 'get_jitcell_at_key', - False) + m = _find_jit_markers(self.translator.graphs, + ('get_jitcell_at_key', 'trace_next_iteration')) accessors = {} - def get_accessor(jitdriver_name, function, ARGS): - a = accessors.get(jitdriver_name) + def get_accessor(name, jitdriver_name, function, ARGS): + a = accessors.get((name, jitdriver_name)) if a: return a d = {'function': function, @@ -622,7 +633,7 @@ """ % (arg_spec, arg_spec)).compile() in d FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) ll_ptr = self.helper_func(FUNC, d['accessor']) - accessors[jitdriver_name] = ll_ptr + accessors[(name, jitdriver_name)] = ll_ptr return ll_ptr for graph, block, index in m: @@ -630,7 +641,12 @@ jitdriver_name = op.args[1].value JitCell = jitdrivers_by_name[jitdriver_name].warmstate.JitCell ARGS = [x.concretetype for x in op.args[2:]] - accessor = get_accessor(jitdriver_name, JitCell.get_jitcell, + if op.args[0].value == 'get_jitcell_at_key': + func = JitCell.get_jitcell + else: + func = JitCell._trace_next_iteration + accessor = get_accessor(op.args[0].value, + jitdriver_name, func, ARGS) v_result = op.result c_accessor = Constant(accessor, concretetype=lltype.Void) diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -545,6 +545,10 @@ @staticmethod def trace_next_iteration(greenkey): greenargs = unwrap_greenkey(greenkey) + JitCell._trace_next_iteration(*greenargs) + + @staticmethod + def _trace_next_iteration(*greenargs): hash = JitCell.get_uhash(*greenargs) jitcounter.change_current_fraction(hash, 0.98) diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -149,3 +149,21 @@ for i, arg in enumerate(hop.args_r[1:])] return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, resulttype=hop.r_result) + +def trace_next_iteration(name, *greenkey): + raise Exception("need to run translated") + +class TraceNextIterationEntry(ExtRegistryEntry): + _about_ = trace_next_iteration + + def compute_result_annotation(self, s_name, *args_s): + assert s_name.is_constant() + + def specialize_call(self, hop): + c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) + c_name = Constant("trace_next_iteration", concretetype=lltype.Void) + hop.exception_cannot_occur() + args_v = [hop.inputarg(arg, arg=i + 1) + for i, arg in enumerate(hop.args_r[1:])] + return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, + resulttype=hop.r_result) From noreply at buildbot.pypy.org Mon Sep 14 11:15:07 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 11:15:07 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: implement dont_trace_here hook Message-ID: <20150914091507.4BD8A1C12D4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79614:df24639b3a95 Date: 2015-09-14 11:15 +0200 http://bitbucket.org/pypy/pypy/changeset/df24639b3a95/ Log: implement dont_trace_here hook 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 @@ -1582,8 +1582,9 @@ resbox = self.metainterp.execute_and_record_varargs( rop.CALL_MAY_FORCE_F, allboxes, descr=descr) elif tp == 'v': - resbox = self.metainterp.execute_and_record_varargs( + self.metainterp.execute_and_record_varargs( rop.CALL_MAY_FORCE_N, allboxes, descr=descr) + resbox = None else: assert False self.metainterp.vrefs_after_residual_call() @@ -2961,6 +2962,8 @@ opnum = OpHelpers.call_assembler_for_descr(op.getdescr()) op = op.copy_and_change(opnum, args=args, descr=token) self.history.operations.append(op) + if opnum == rop.CALL_ASSEMBLER_N: + op = None # # To fix an obscure issue, make sure the vable stays alive # longer than the CALL_ASSEMBLER operation. We do it by diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -175,6 +175,31 @@ self.meta_interp(main, [5]) self.check_jitcell_token_count(2) + def test_dont_trace_here(self): + driver = JitDriver(greens = ['s'], reds = ['i', 'k'], name='jit') + + def loop(i, s): + k = 4 + while i > 0: + driver.jit_merge_point(k=k, i=i, s=s) + if s == 1: + loop(3, 0) + k -= 1 + i -= 1 + if k == 0: + k = 4 + driver.can_enter_jit(k=k, i=i, s=s) + + def main(s, check): + if check: + jit_hooks.dont_trace_here("jit", 0) + loop(30, s) + + self.meta_interp(main, [1, 0], inline=True) + self.check_resops(call_assembler_n=0) + self.meta_interp(main, [1, 1], inline=True) + self.check_resops(call_assembler_n=8) + class LLJitHookInterfaceTests(JitHookInterfaceTests): # use this for any backend, instead of the super class diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -617,7 +617,8 @@ if name != 'jitdriver': jitdrivers_by_name[name] = jd m = _find_jit_markers(self.translator.graphs, - ('get_jitcell_at_key', 'trace_next_iteration')) + ('get_jitcell_at_key', 'trace_next_iteration', + 'dont_trace_here')) accessors = {} def get_accessor(name, jitdriver_name, function, ARGS): @@ -627,12 +628,20 @@ d = {'function': function, 'cast_instance_to_gcref': cast_instance_to_gcref} arg_spec = ", ".join([("arg%d" % i) for i in range(len(ARGS))]) - exec py.code.Source(""" - def accessor(%s): - return cast_instance_to_gcref(function(%s)) - """ % (arg_spec, arg_spec)).compile() in d - FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) - ll_ptr = self.helper_func(FUNC, d['accessor']) + if name == 'get_jitcell_at_key': + exec py.code.Source(""" + def accessor(%s): + return cast_instance_to_gcref(function(%s)) + """ % (arg_spec, arg_spec)).compile() in d + FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) + else: + exec py.code.Source(""" + def accessor(%s): + function(%s) + """ % (arg_spec, arg_spec)).compile() in d + FUNC = lltype.Ptr(lltype.FuncType(ARGS, lltype.Void)) + func = d['accessor'] + ll_ptr = self.helper_func(FUNC, func) accessors[(name, jitdriver_name)] = ll_ptr return ll_ptr @@ -643,6 +652,8 @@ ARGS = [x.concretetype for x in op.args[2:]] if op.args[0].value == 'get_jitcell_at_key': func = JitCell.get_jitcell + elif op.args[0].value == 'dont_trace_here': + func = JitCell.dont_trace_here else: func = JitCell._trace_next_iteration accessor = get_accessor(op.args[0].value, diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -555,6 +555,10 @@ @staticmethod def ensure_jit_cell_at_key(greenkey): greenargs = unwrap_greenkey(greenkey) + return JitCell._ensure_jit_cell_at_key(*greenargs) + + @staticmethod + def _ensure_jit_cell_at_key(*greenargs): hash = JitCell.get_uhash(*greenargs) cell = jitcounter.lookup_chain(hash) while cell is not None: @@ -565,6 +569,11 @@ newcell = JitCell(*greenargs) jitcounter.install_new_cell(hash, newcell) return newcell + + @staticmethod + def dont_trace_here(*greenargs): + cell = JitCell._ensure_jit_cell_at_key(*greenargs) + cell.flags |= JC_DONT_TRACE_HERE # self.JitCell = JitCell return JitCell diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -131,39 +131,29 @@ # ---------------------- jitcell interface ---------------------- -def get_jitcell_at_key(name, *greenkey): - raise Exception("need to run translated") +def _new_hook(name, resulttype): + def hook(name, *greenkey): + raise Exception("need to run translated") + hook.func_name = name -class GetJitCellEntry(ExtRegistryEntry): - _about_ = get_jitcell_at_key + class GetJitCellEntry(ExtRegistryEntry): + _about_ = hook - def compute_result_annotation(self, s_name, *args_s): - assert s_name.is_constant() - return SomePtr(llmemory.GCREF) + def compute_result_annotation(self, s_name, *args_s): + assert s_name.is_constant() + return resulttype - def specialize_call(self, hop): - c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) - c_name = Constant("get_jitcell_at_key", concretetype=lltype.Void) - hop.exception_cannot_occur() - args_v = [hop.inputarg(arg, arg=i + 1) - for i, arg in enumerate(hop.args_r[1:])] - return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, - resulttype=hop.r_result) + def specialize_call(self, hop): + c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) + c_name = Constant(name, concretetype=lltype.Void) + hop.exception_cannot_occur() + args_v = [hop.inputarg(arg, arg=i + 1) + for i, arg in enumerate(hop.args_r[1:])] + return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, + resulttype=hop.r_result) -def trace_next_iteration(name, *greenkey): - raise Exception("need to run translated") + return hook -class TraceNextIterationEntry(ExtRegistryEntry): - _about_ = trace_next_iteration - - def compute_result_annotation(self, s_name, *args_s): - assert s_name.is_constant() - - def specialize_call(self, hop): - c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) - c_name = Constant("trace_next_iteration", concretetype=lltype.Void) - hop.exception_cannot_occur() - args_v = [hop.inputarg(arg, arg=i + 1) - for i, arg in enumerate(hop.args_r[1:])] - return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, - resulttype=hop.r_result) +get_jitcell_at_key = _new_hook('get_jitcell_at_key', SomePtr(llmemory.GCREF)) +trace_next_iteration = _new_hook('trace_next_iteration', None) +dont_trace_here = _new_hook('dont_trace_here', None) From noreply at buildbot.pypy.org Mon Sep 14 11:22:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 11:22:12 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: expose at applevel Message-ID: <20150914092212.A591D1C12D4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79615:615b7ca9e23a Date: 2015-09-14 11:22 +0200 http://bitbucket.org/pypy/pypy/changeset/615b7ca9e23a/ Log: expose at applevel diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,6 +8,9 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', + 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', + 'dont_trace_here': 'interp_jit.dont_trace_here', + 'trace_next_iteration': 'interp_jit.trace_next_iteration', #'set_compile_hook': 'interp_resop.set_compile_hook', #'set_optimize_hook': 'interp_resop.set_optimize_hook', #'set_abort_hook': 'interp_resop.set_abort_hook', diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -5,11 +5,13 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside -from rpython.rlib import jit +from rpython.rlib import jit, jit_hooks from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.pycode import CO_GENERATOR, PyCode +from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame, Yield from pypy.interpreter.baseobjspace import W_Root @@ -188,3 +190,23 @@ __call__ = interp2app(W_NotFromAssembler.descr_call), ) W_NotFromAssembler.typedef.acceptable_as_base_class = False + + at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) +def get_jitcell_at_key(space, next_instr, is_being_profiled, pycode): + ll_pycode = cast_instance_to_gcref(pycode) + return space.wrap(bool(jit_hooks.get_jitcell_at_key( + 'pypyjit', next_instr, int(is_being_profiled), ll_pycode))) + + at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) +def dont_trace_here(space, next_instr, is_being_profiled, pycode): + ll_pycode = cast_instance_to_gcref(pycode) + jit_hooks.dont_trace_here( + 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) +def trace_next_iteration(space, next_instr, is_being_profiled, pycode): + ll_pycode = cast_instance_to_gcref(pycode) + jit_hooks.trace_next_iteration( + 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) + return space.w_None From noreply at buildbot.pypy.org Mon Sep 14 11:24:33 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 11:24:33 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: bow to the complaints Message-ID: <20150914092433.714471C12D4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79616:5fa71a34f940 Date: 2015-09-14 11:24 +0200 http://bitbucket.org/pypy/pypy/changeset/5fa71a34f940/ Log: bow to the complaints diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -191,22 +191,22 @@ ) W_NotFromAssembler.typedef.acceptable_as_base_class = False - at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) -def get_jitcell_at_key(space, next_instr, is_being_profiled, pycode): - ll_pycode = cast_instance_to_gcref(pycode) + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) +def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) return space.wrap(bool(jit_hooks.get_jitcell_at_key( 'pypyjit', next_instr, int(is_being_profiled), ll_pycode))) - at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) -def dont_trace_here(space, next_instr, is_being_profiled, pycode): - ll_pycode = cast_instance_to_gcref(pycode) + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) +def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.dont_trace_here( 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) return space.w_None - at unwrap_spec(next_instr=int, is_being_profiled=bool, pycode=PyCode) -def trace_next_iteration(space, next_instr, is_being_profiled, pycode): - ll_pycode = cast_instance_to_gcref(pycode) + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) +def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.trace_next_iteration( 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) return space.w_None From noreply at buildbot.pypy.org Mon Sep 14 11:41:18 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 11:41:18 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: don't look into those functions Message-ID: <20150914094118.6AB701C0748@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79617:84812c89457a Date: 2015-09-14 11:41 +0200 http://bitbucket.org/pypy/pypy/changeset/84812c89457a/ Log: don't look into those functions diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -192,12 +192,14 @@ W_NotFromAssembler.typedef.acceptable_as_base_class = False @unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) return space.wrap(bool(jit_hooks.get_jitcell_at_key( 'pypyjit', next_instr, int(is_being_profiled), ll_pycode))) @unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.dont_trace_here( @@ -205,6 +207,7 @@ return space.w_None @unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.trace_next_iteration( From noreply at buildbot.pypy.org Mon Sep 14 12:05:03 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 12:05:03 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: a hackish fix Message-ID: <20150914100503.783651C1F50@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79618:70f760f9ce29 Date: 2015-09-14 12:05 +0200 http://bitbucket.org/pypy/pypy/changeset/70f760f9ce29/ Log: a hackish fix diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -5,7 +5,7 @@ from rpython.jit.metainterp.test.support import LLJitMixin from rpython.jit.codewriter.policy import JitPolicy from rpython.jit.metainterp.resoperation import rop -from rpython.rtyper.annlowlevel import hlstr +from rpython.rtyper.annlowlevel import hlstr, cast_instance_to_gcref from rpython.jit.metainterp.jitprof import Profiler, EmptyProfiler @@ -175,6 +175,32 @@ self.meta_interp(main, [5]) self.check_jitcell_token_count(2) + def test_get_jitcell_at_key_ptr(self): + driver = JitDriver(greens = ['s'], reds = ['i'], name='jit') + + class Green(object): + pass + + def loop(i, s): + while i > 0: + driver.jit_merge_point(i=i, s=s) + i -= 1 + + def main(s): + g1 = Green() + g2 = Green() + g1_ptr = cast_instance_to_gcref(g1) + g2_ptr = cast_instance_to_gcref(g2) + loop(10, g1) + assert jit_hooks.get_jitcell_at_key("jit", g1_ptr) + assert not jit_hooks.get_jitcell_at_key("jit", g2_ptr) + jit_hooks.trace_next_iteration("jit", g2_ptr) + loop(2, g2) + assert jit_hooks.get_jitcell_at_key("jit", g2_ptr) + + self.meta_interp(main, [5]) + self.check_jitcell_token_count(2) + def test_dont_trace_here(self): driver = JitDriver(greens = ['s'], reds = ['i', 'k'], name='jit') diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -621,24 +621,33 @@ 'dont_trace_here')) accessors = {} - def get_accessor(name, jitdriver_name, function, ARGS): + def get_accessor(name, jitdriver_name, function, ARGS, green_arg_spec): a = accessors.get((name, jitdriver_name)) if a: return a d = {'function': function, - 'cast_instance_to_gcref': cast_instance_to_gcref} + 'cast_instance_to_gcref': cast_instance_to_gcref, + 'lltype': lltype} arg_spec = ", ".join([("arg%d" % i) for i in range(len(ARGS))]) + arg_converters = [] + for i, spec in enumerate(green_arg_spec): + if isinstance(spec, lltype.Ptr): + arg_converters.append("arg%d = lltype.cast_opaque_ptr(type%d, arg%d)" % (i, i, i)) + d['type%d' % i] = spec + convert = ";".join(arg_converters) if name == 'get_jitcell_at_key': exec py.code.Source(""" def accessor(%s): + %s return cast_instance_to_gcref(function(%s)) - """ % (arg_spec, arg_spec)).compile() in d + """ % (arg_spec, convert, arg_spec)).compile() in d FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) else: exec py.code.Source(""" def accessor(%s): + %s function(%s) - """ % (arg_spec, arg_spec)).compile() in d + """ % (arg_spec, convert, arg_spec)).compile() in d FUNC = lltype.Ptr(lltype.FuncType(ARGS, lltype.Void)) func = d['accessor'] ll_ptr = self.helper_func(FUNC, func) @@ -656,9 +665,10 @@ func = JitCell.dont_trace_here else: func = JitCell._trace_next_iteration + argspec = jitdrivers_by_name[jitdriver_name]._green_args_spec accessor = get_accessor(op.args[0].value, jitdriver_name, func, - ARGS) + ARGS, argspec) v_result = op.result c_accessor = Constant(accessor, concretetype=lltype.Void) newop = SpaceOperation('direct_call', [c_accessor] + op.args[2:], From noreply at buildbot.pypy.org Mon Sep 14 12:08:45 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 12:08:45 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: fix Message-ID: <20150914100845.A9E771C1F5F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79619:a548405b60ae Date: 2015-09-14 12:08 +0200 http://bitbucket.org/pypy/pypy/changeset/a548405b60ae/ Log: fix diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -196,14 +196,14 @@ def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) return space.wrap(bool(jit_hooks.get_jitcell_at_key( - 'pypyjit', next_instr, int(is_being_profiled), ll_pycode))) + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode))) @unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) @dont_look_inside def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.dont_trace_here( - 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) return space.w_None @unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) @@ -211,5 +211,5 @@ def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): ll_pycode = cast_instance_to_gcref(w_pycode) jit_hooks.trace_next_iteration( - 'pypyjit', next_instr, int(is_being_profiled), ll_pycode) + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) return space.w_None From noreply at buildbot.pypy.org Mon Sep 14 12:40:32 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 12:40:32 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Say that the non-sse2 version might work but is untested. Message-ID: <20150914104032.7A2911C12D4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r635:43812543cae6 Date: 2015-09-14 12:41 +0200 http://bitbucket.org/pypy/pypy.org/changeset/43812543cae6/ Log: Say that the non-sse2 version might work but is untested. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -161,8 +161,8 @@ mirror, but please use only if you have troubles accessing the links above

If your CPU is really, really old, it may be a x86-32 without SSE2. -We could at some point make a PyPy with a JIT without SSE2 –ask us -on IRC if you really want to know more– but note that your machine +There is untested support for manually translating PyPy's JIT without +SSE2 (--jit-backend=x86-without-sse2) but note that your machine is probably low-spec enough that running CPython on it is a better idea in the first place.

[1]: stating it again: the Linux binaries are provided for the diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -132,8 +132,8 @@ .. __: https://bitbucket.org/pypy/pypy/downloads If your CPU is really, really old, it may be a x86-32 without SSE2. -We could at some point make a PyPy with a JIT without SSE2 ---ask us -on IRC if you really want to know more--- but note that your machine +There is untested support for manually translating PyPy's JIT without +SSE2 (``--jit-backend=x86-without-sse2``) but note that your machine is probably low-spec enough that running CPython on it is a better idea in the first place. From noreply at buildbot.pypy.org Mon Sep 14 13:10:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 13:10:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix for a segfault in itertools.islice() Message-ID: <20150914111043.35D891C0748@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79620:77772e44a71f Date: 2015-09-14 13:10 +0200 http://bitbucket.org/pypy/pypy/changeset/77772e44a71f/ Log: Test and fix for a segfault in itertools.islice() diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -407,11 +407,12 @@ raise def _ignore_items(self, num): - if self.iterable is None: + w_iterator = self.iterable + if w_iterator is None: raise OperationError(self.space.w_StopIteration, self.space.w_None) while True: try: - self.space.next(self.iterable) + self.space.next(w_iterator) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): self.iterable = None diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -1085,3 +1085,18 @@ assert list(itertools.islice(c2, 3)) == expected c3 = pickle.loads(pickle.dumps(c)) assert list(itertools.islice(c3, 3)) == expected + + def test_islice_attack(self): + import itertools + class Iterator(object): + first = True + def __iter__(self): + return self + def next(self): + if self.first: + self.first = False + list(islice) + return 52 + myiter = Iterator() + islice = itertools.islice(myiter, 5, 8) + raises(StopIteration, islice.next) From noreply at buildbot.pypy.org Mon Sep 14 13:13:32 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 13:13:32 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue #2135: Add a jitdriver Message-ID: <20150914111332.7E0AE1C0748@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79621:bff7d2bb8c4a Date: 2015-09-14 13:13 +0200 http://bitbucket.org/pypy/pypy/changeset/bff7d2bb8c4a/ Log: Issue #2135: Add a jitdriver diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from rpython.rlib import jit class W_Count(W_Root): @@ -322,6 +323,11 @@ """) +islice_ignore_items_driver = jit.JitDriver(name='islice_ignore_items', + greens=['tp'], + reds=['num', 'w_islice', + 'w_iterator']) + class W_ISlice(W_Root): def __init__(self, space, w_iterable, w_startstop, args_w): self.iterable = space.iter(w_iterable) @@ -410,7 +416,13 @@ w_iterator = self.iterable if w_iterator is None: raise OperationError(self.space.w_StopIteration, self.space.w_None) + + tp = self.space.type(w_iterator) while True: + islice_ignore_items_driver.jit_merge_point(tp=tp, + num=num, + w_islice=self, + w_iterator=w_iterator) try: self.space.next(w_iterator) except OperationError as e: From noreply at buildbot.pypy.org Mon Sep 14 13:31:41 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 14 Sep 2015 13:31:41 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: slowly approaching the first passing scheduling test, code is smaller and more compact Message-ID: <20150914113141.7D0E31C130D@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79622:289407699445 Date: 2015-09-14 13:31 +0200 http://bitbucket.org/pypy/pypy/changeset/289407699445/ Log: slowly approaching the first passing scheduling test, code is smaller and more compact diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -355,7 +355,7 @@ def __repr__(self): pack = '' if self.pack: - pack = "p: %d" % self.pack.opcount() + pack = "p: %d" % self.pack.numops() return "Node(%s,%s i: %d)" % (self.op.getopname(), pack, self.opidx) def __ne__(self, other): diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -18,7 +18,7 @@ def post_schedule(self): loop = self.graph.loop - self.renamer.rename(loop.label.getoperation()) + self.renamer.rename(loop.jump) def profitable(self): return self.costmodel.profitable() @@ -66,7 +66,7 @@ Keeps worklist sorted (see priority) """ op = node.getoperation() state.renamer.rename(op) - state.unpack_from_vector(op, self) + state.unpack_from_vector(op) node.position = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY @@ -97,6 +97,7 @@ """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) + import pdb; pdb.set_trace() while state.has_more(): node = self.next(state) if node: @@ -177,40 +178,43 @@ rop.UINT_LT, rop.UINT_LE, rop.UINT_GT, rop.UINT_GE) -class Type(object): - """ The type of one operation. Saves type, size and sign. """ - @staticmethod - def of(op): - descr = op.getdescr() - if descr: - type = INT - if descr.is_array_of_floats() or descr.concrete_type == FLOAT: - type = FLOAT - size = descr.get_item_size_in_bytes() - sign = descr.is_item_signed() - return Type(type, size, sign) - else: - size = 8 - sign = True - if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: - sign = False - return Type(op.type, size, sign) - - def __init__(self, type, size, signed): - assert type in (FLOAT, INT) - self.type = type - self.size = size - self.signed = signed - - def clone(self): - return Type(self.type, self.size, self.signed) - - def __repr__(self): - sign = '-' - if not self.signed: - sign = '+' - return 'Type(%s%s, %d)' % (sign, self.type, self.size) - +#class Type(object): +# """ The type of one operation. Saves type, size and sign. """ +# @staticmethod +# def of(op): +# descr = op.getdescr() +# if descr: +# type = INT +# if descr.is_array_of_floats() or descr.concrete_type == FLOAT: +# type = FLOAT +# size = descr.get_item_size_in_bytes() +# sign = descr.is_item_signed() +# return Type(type, size, sign) +# else: +# size = 8 +# sign = True +# if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: +# sign = False +# return Type(op.type, size, sign) +# +# def __init__(self, type, size, signed): +# assert type in (FLOAT, INT) +# self.type = type +# self.size = size +# self.signed = signed +# +# def bytecount(self): +# return self.size +# +# def clone(self): +# return Type(self.type, self.size, self.signed) +# +# def __repr__(self): +# sign = '-' +# if not self.signed: +# sign = '+' +# return 'Type(%s%s, %d)' % (sign, self.type, self.size) +# #UNKNOWN_TYPE = '-' #@staticmethod @@ -268,10 +272,6 @@ #def getcount(self): # return self.count - #def pack_byte_size(self, pack): - # if len(pack.operations) == 0: - # return 0 - # return self.getsize() * pack.opcount() class TypeRestrict(object): ANY_TYPE = -1 @@ -301,6 +301,20 @@ self.type = type self.count = count + + def bytecount(self): + return self.count * self.type.bytecount() + +class DataTyper(object): + + def infer_type(self, op): + # default action, pass through: find the first arg + # the output is the same as the first argument! + if op.returns_void() or op.argcount() == 0: + return + arg0 = op.getarg(0) + op.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + class PassFirstArg(TypeOutput): def __init__(self): pass @@ -316,17 +330,14 @@ op = pack.leftmost() args = op.getarglist() self.prepare_arguments(state, op.getarglist()) - # - vop = VecOperation(op.vector, args, otype. op.getdescr()) - #result = self.transform_result(op) + vop = VecOperation(op.vector, args, op, pack.numops(), op.getdescr()) # if op.is_guard(): assert isinstance(op, GuardResOp) assert isinstance(vop, GuardResOp) vop.setfailargs(op.getfailargs()) vop.rd_snapshot = op.rd_snapshot - self.vecops.append(vop) - self.costmodel.record_pack_savings(self.pack, self.pack.opcount()) + state.costmodel.record_pack_savings(pack, pack.numops()) # if pack.is_accumulating(): box = oplist[position].result @@ -335,8 +346,10 @@ op = node.getoperation() assert not op.returns_void() scheduler.renamer.start_renaming(op, box) + # + state.oplist.append(vop) - def transform_arguments(self, state, args): + def prepare_arguments(self, state, args): self.before_argument_transform(args) # Transforming one argument to a vector box argument # The following cases can occur: @@ -732,12 +745,12 @@ def __init__(self): OpToVectorOp.__init__(self, (), TypeRestrict()) - def before_argument_transform(self, args): - count = min(self.output_type.getcount(), len(self.getoperations())) - args.append(ConstInt(count)) + # OLD def before_argument_transform(self, args): + #count = min(self.output_type.getcount(), len(self.getoperations())) + #args.append(ConstInt(count)) def get_output_type_given(self, input_type, op): - return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) def get_input_type_given(self, output_type, op): return None @@ -760,7 +773,7 @@ return None def get_input_type_given(self, output_type, op): - return Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) + return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) class PassThroughOp(OpToVectorOp): """ This pass through is only applicable if the target @@ -778,7 +791,7 @@ class trans(object): - PASS = PassFirstArg() + DT_PASS = DataTyper() TR_ANY_FLOAT = TypeRestrict(FLOAT) TR_ANY_INTEGER = TypeRestrict(INT) @@ -787,9 +800,9 @@ TR_LONG = TypeRestrict(INT, 8, 2) TR_INT_2 = TypeRestrict(INT, 4, 2) - INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), PASS) - FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), PASS) - FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), PASS) + INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), DT_PASS) + FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), DT_PASS) + FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), DT_PASS) LOAD = LoadToVectorLoad() STORE = StoreToVectorStore() GUARD = PassThroughOp((TR_ANY_INTEGER,)) @@ -839,6 +852,11 @@ rop.VEC_INT_IS_TRUE: OpToVectorOp((TR_ANY_INTEGER,TR_ANY_INTEGER), None), # TR_ANY_INTEGER), } + # TODO? + UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, + rop.UINT_LT, rop.UINT_LE, + rop.UINT_GT, rop.UINT_GE) + def determine_input_output_types(pack, node, forward): """ This function is two fold. If moving forward, it gets an input type from the packs output type and returns @@ -888,9 +906,11 @@ def post_schedule(self): loop = self.graph.loop - self.sched_data.unpack_from_vector(loop.jump.getoperation(), self) + self.unpack_from_vector(loop.jump) SchedulerState.post_schedule(self) + self.graph.loop.operations = self.oplist + # add accumulation info to the descriptor #for version in self.loop.versions: # # this needs to be done for renamed (accum arguments) @@ -928,11 +948,11 @@ to emit the actual operation into the oplist of the scheduler. """ if node.pack: + assert node.pack.numops() > 1 for node in node.pack.operations: scheduler.mark_emitted(node, self) - assert node.pack.opcount() > 1 - op2vecop = determine_trans(node.pack.leftmost()) - op2vecop.as_vector_operation(self, node.pack) + op2vecop = determine_trans(node.pack.leftmost()) + op2vecop.as_vector_operation(self, node.pack) return True return False @@ -950,7 +970,7 @@ return True return False - def unpack_from_vector(self, op, scheduler): + def unpack_from_vector(self, op): """ If a box is needed that is currently stored within a vector box, this utility creates a unpacking instruction. """ @@ -959,7 +979,7 @@ # unpack for an immediate use for i, arg in enumerate(op.getarglist()): if not arg.is_constant(): - argument = self._unpack_from_vector(i, arg, scheduler) + argument = self._unpack_from_vector(i, arg) if arg is not argument: op.setarg(i, argument) if not op.returns_void(): @@ -969,11 +989,11 @@ fail_args = op.getfailargs() for i, arg in enumerate(fail_args): if arg and not arg.is_constant(): - argument = self._unpack_from_vector(i, arg, scheduler) + argument = self._unpack_from_vector(i, arg) if arg is not argument: fail_args[i] = argument - def _unpack_from_vector(self, i, arg, scheduler): + def _unpack_from_vector(self, i, arg): if arg in self.seen or arg.type == 'V': return arg (j, vbox) = self.getvector_of_box(arg) @@ -982,14 +1002,14 @@ return arg arg_cloned = arg.clonebox() self.seen[arg_cloned] = None - scheduler.renamer.start_renaming(arg, arg_cloned) + self.renamer.start_renaming(arg, arg_cloned) self.setvector_of_box(arg_cloned, j, vbox) cj = ConstInt(j) ci = ConstInt(1) opnum = getunpackopnum(vbox.gettype()) unpack_op = ResOperation(opnum, [vbox, cj, ci], arg_cloned) self.costmodel.record_vector_unpack(vbox, j, 1) - scheduler.oplist.append(unpack_op) + self.oplist.append(unpack_op) return arg_cloned return arg @@ -1042,15 +1062,19 @@ """ FULL = 0 - def __init__(self, ops, input_type, output_type): + def __init__(self, ops): self.operations = ops self.accum = None - self.input_type = input_type - self.output_type = output_type - assert self.input_type is not None or self.output_type is not None self.update_pack_of_nodes() + # initializes the type + # TODO + #input_type, output_type = \ + # determine_input_output_types(origin_pack, lnode, forward) + #self.input_type = input_type + #self.output_type = output_type + #assert self.input_type is not None or self.output_type is not None - def opcount(self): + def numops(self): return len(self.operations) def leftmost(self): @@ -1078,22 +1102,25 @@ return self._byte_size(self.output_type) def pack_load(self, vec_reg_size): - """ Returns the load of the pack. A value - smaller than 0 indicates that it is empty - or nearly empty, zero indicates that all slots - are used and > 0 indicates that too many operations - are in this pack instance. + """ Returns the load of the pack a vector register would hold + just after executing the operation. + returns: < 0 - empty, nearly empty + = 0 - full + > 0 - overloaded """ - if len(self.operations) == 0: + left = self.leftmost() + if left.returns_void(): + return 0 + if self.numops() == 0: return -1 size = maximum_byte_size(self, vec_reg_size) - if self.input_type is None: + return left.bytesize * self.numops() - size + #if self.input_type is None: # e.g. load operations - return self.output_type.pack_byte_size(self) - size + # return self.output_type.bytecount(self) - size # default only consider the input type # e.g. store operations, int_add, ... - return self.input_type.pack_byte_size(self) - size - + #return self.input_type.bytecount(self) - size def is_full(self, vec_reg_size): """ If one input element times the opcount is equal @@ -1131,12 +1158,14 @@ newpack = pack.clone(newoplist) load = newpack.pack_load(vec_reg_size) if load >= Pack.FULL: + pack.update_pack_of_nodes() pack = newpack packlist.append(newpack) else: newpack.clear() newpack.operations = [] break + pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): count = opcount_filling_vector_register(self, vec_reg_size) @@ -1163,31 +1192,26 @@ def __repr__(self): if len(self.operations) == 0: - return "Pack(-, [])" - opname = self.operations[0].getoperation().getopname() - return "Pack(%s,%r)" % (opname, self.operations) + return "Pack(empty)" + return "Pack(%dx %s)" % (self.numops(), self.operations[0]) def is_accumulating(self): return self.accum is not None def clone(self, oplist): - cloned = Pack(oplist, self.input_type, self.output_type) + cloned = Pack(oplist) cloned.accum = self.accum return cloned class Pair(Pack): """ A special Pack object with only two statements. """ - def __init__(self, left, right, input_type, output_type): + def __init__(self, left, right): assert isinstance(left, Node) assert isinstance(right, Node) self.left = left self.right = right - if input_type: - input_type = input_type.clone() - if output_type: - output_type = output_type.clone() - Pack.__init__(self, [left, right], input_type, output_type) + Pack.__init__(self, [left, right]) def __eq__(self, other): if isinstance(other, Pair): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -7,7 +7,7 @@ Pack, Pair, NotAProfitableLoop, VectorizingOptimizer, X86_CostModel, PackSet) from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph -from rpython.jit.metainterp.optimizeopt.schedule import Type, Scheduler +from rpython.jit.metainterp.optimizeopt.schedule import Scheduler from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest, FakeDependencyGraph) @@ -17,13 +17,13 @@ from rpython.jit.tool.oparser import parse as opparse from rpython.jit.tool.oparser_model import get_model -F64 = Type('f',8,False) -F32 = Type('f',4,False) -F32_2 = Type('f',4,False) -I64 = Type('i',8,True) -I32 = Type('i',4,True) -I32_2 = Type('i',4,True) -I16 = Type('i',2,True) +F64 = None #('f',8,False) +F32 = None #('f',4,False) +F32_2 = None #('f',4,False) +I64 = None #('i',8,True) +I32 = None #('i',4,True) +I32_2 = None #('i',4,True) +I16 = None #('i',2,True) class FakePackSet(PackSet): def __init__(self, packs): @@ -68,7 +68,7 @@ return loop def pack(self, loop, l, r, input_type, output_type): - return Pack(loop.graph.nodes[1+l:1+r], input_type, output_type) + return Pack(loop.graph.nodes[1+l:1+r]) def schedule(self, loop, packs, vec_reg_size=16, prepend_invariant=False, overwrite_funcs=None): @@ -79,7 +79,7 @@ for i in range(len(pack.operations)-1): o1 = pack.operations[i] o2 = pack.operations[i+1] - pair = Pair(o1,o2,pack.input_type,pack.output_type) + pair = Pair(o1,o2) pairs.append(pair) packset = FakePackSet(pairs) state = VecScheduleState(loop.graph, packset, self.cpu, cm) @@ -94,6 +94,9 @@ state.prepend_invariant_operations = lambda list, _: list opt.combine_packset() opt.schedule(state) + # works for now. might be the wrong class? + # wrap label + operations + jump it in tree loop otherwise + return state.graph.loop class Test(SchedulerBaseTest, LLtypeMixin): @@ -124,7 +127,7 @@ pack1 = self.pack(loop1, 0, 6, None, F32) loop2 = self.schedule(loop1, [pack1]) loop3 = self.parse_trace(""" - v10[i32|4] = vec_raw_load_i(p0, i0, 4, descr=float) + v10[4xi32] = vec_raw_load_i(p0, i0, descr=float) f10 = raw_load_f(p0, i4, descr=float) f11 = raw_load_f(p0, i5, descr=float) """, False) @@ -144,7 +147,7 @@ pack3 = self.pack(loop1, 4, 6, I32_2, F32_2) loop2 = self.schedule(loop1, [pack1, pack2, pack3]) loop3 = self.parse_trace(""" - v10[i64|2] = vec_raw_load_i(p0, i0, 2, descr=long) + v10[i64|2] = vec_raw_load_i(p0, i0, descr=long) v20[i32|2] = vec_int_signext(v10[i64|2], 4) v30[f64|2] = vec_cast_int_to_float(v20[i32|2]) """, False) @@ -268,7 +271,7 @@ """) pack1 = self.pack(loop1, 0, 8, None, F64) pack2 = self.pack(loop1, 8, 16, F64, I32_2) - I16_2 = Type('i',2,True) + I16_2 = None #Type('i',2,True) pack3 = self.pack(loop1, 16, 24, I32_2, I16_2) pack4 = self.pack(loop1, 24, 32, I16, None) def void(b,c): @@ -278,10 +281,10 @@ '_prevent_signext': void }) loop3 = self.parse_trace(""" - v10[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) - v11[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) - v12[f64|2] = vec_raw_load_f(p0, i5, 2, descr=double) - v13[f64|2] = vec_raw_load_f(p0, i7, 2, descr=double) + v10[f64|2] = vec_raw_load_f(p0, i1, descr=double) + v11[f64|2] = vec_raw_load_f(p0, i3, descr=double) + v12[f64|2] = vec_raw_load_f(p0, i5, descr=double) + v13[f64|2] = vec_raw_load_f(p0, i7, descr=double) v14[i32|2] = vec_cast_float_to_int(v10[f64|2]) v15[i32|2] = vec_cast_float_to_int(v11[f64|2]) v16[i32|2] = vec_cast_float_to_int(v12[f64|2]) @@ -319,8 +322,8 @@ pack3 = self.pack(loop1, 8, 12, I32, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3]) loop3 = self.parse_trace(""" - v44[f64|2] = vec_raw_load_f(p0, i1, 2, descr=double) - v45[f64|2] = vec_raw_load_f(p0, i3, 2, descr=double) + v44[f64|2] = vec_raw_load_f(p0, i1, descr=double) + v45[f64|2] = vec_raw_load_f(p0, i3, descr=double) v46[i32|2] = vec_cast_float_to_singlefloat(v44[f64|2]) v47[i32|2] = vec_cast_float_to_singlefloat(v45[f64|2]) v41[i32|4] = vec_int_pack(v46[i32|2], v47[i32|2], 2, 2) @@ -345,7 +348,7 @@ loop2 = self.schedule(loop1, [pack1,pack2,pack3], prepend_invariant=True) loop3 = self.parse_trace(""" v9[i64|2] = vec_int_expand(255,2) - v10[i64|2] = vec_raw_load_i(p0, i1, 2, descr=long) + v10[i64|2] = vec_raw_load_i(p0, i1, descr=long) v11[i64|2] = vec_int_and(v10[i64|2], v9[i64|2]) guard_true(v11[i64|2]) [] """, False) @@ -365,7 +368,7 @@ pack2 = self.pack(loop1, 4, 6, I32_2, None) loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i32|4] = vec_raw_load_i(p0, i1, 4, descr=float) + v1[i32|4] = vec_raw_load_i(p0, i1, descr=float) i10 = vec_int_unpack(v1[i32|4], 0, 1) raw_store(p0, i3, i10, descr=float) i11 = vec_int_unpack(v1[i32|4], 1, 1) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -22,7 +22,7 @@ from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, - getunpackopnum, Type, determine_input_output_types) + getunpackopnum) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) from rpython.rlib import listsort @@ -453,7 +453,7 @@ state.prepare() scheduler = Scheduler() scheduler.walk_and_emit(state) - if state.profitable(): + if not state.profitable(): return state.post_schedule() @@ -674,15 +674,11 @@ if origin_pack is None: op = lnode.getoperation() if op.is_primitive_load(): - # load outputs value, no input - return Pair(lnode, rnode, None, Type.of(op)) + return Pair(lnode, rnode) else: - # store only has an input - return Pair(lnode, rnode, Type.of(op), None) + return Pair(lnode, rnode) if self.profitable_pack(lnode, rnode, origin_pack, forward): - input_type, output_type = \ - determine_input_output_types(origin_pack, lnode, forward) - return Pair(lnode, rnode, input_type, output_type) + return Pair(lnode, rnode) else: if self.contains_pair(lnode, rnode): return None @@ -734,17 +730,9 @@ operations = pack_i.operations for op in pack_j.operations[1:]: operations.append(op) - input_type = pack_i.input_type - output_type = pack_i.output_type - if input_type: - input_type.combine(pack_j.input_type) - if output_type: - output_type.combine(pack_j.output_type) - pack = Pack(operations, input_type, output_type) + pack = Pack(operations) self.packs[i] = pack - # preserve the accum variable (if present) of the - # left most pack, that is the pack with the earliest - # operation at index 0 in the trace + # preserve the accum variable (if present) pack.accum = pack_i.accum pack_i.accum = pack_j.accum = None @@ -851,6 +839,5 @@ pack.clear() self.packs[i] = None continue - pack.update_pack_of_nodes() self.packs = [pack for pack in self.packs + newpacks if pack] diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -80,21 +80,70 @@ elif op.is_guard(): assert not descr.final_descr op.setdescr(descr) + op.inittype() return op -def VecOperation(opnum, args, type, count, descr=None): +def VecOperation(opnum, args, baseop, count, descr=None): + return VecOperationNew(opnum, args, baseop.datatype, baseop.bytesize, baseop.signed, count, descr) + +def VecOperationNew(opnum, args, datateyp, bytesize, signed, count, descr=None): op = ResOperation(opnum, args, descr) - op.item_type = type - op.item_count = count + op.datatype = datateyp + op.bytesize = bytesize + op.signed = signed + op.count = count return op -class AbstractResOpOrInputArg(AbstractValue): +class Typed(object): + _mixin_ = True + _attrs_ = ('datatype', 'bytesize', 'signed') + + datatype = '\x00' + bytesize = -1 + signed = True + + def inittype(self): + if self.returns_void(): + self.bytesize = 0 + self.datatype = 'v' + return + + if self.is_primitive_array_access(): + descr = self.getdescr() + type = self.type + if descr.is_array_of_floats() or descr.concrete_type == 'f': + type = FLOAT + self.bytesize = descr.get_item_size_in_bytes() + self.sign = descr.is_item_signed() + self.datatype = type + else: + # pass through the type of the first input argument + if self.numargs() == 0: + return + arg0 = self.getarg(0) + self.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + assert self.datatype != '\x00' + assert self.bytesize > 0 + + def setdatatype(self, data_type, bytesize, signed): + self.datatype = data_type + self.bytesize = bytesize + self.signed = signed + + def typestr(self): + sign = '-' + if not self.signed: + sign = '+' + return 'Type(%s%s, %d)' % (sign, self.type, self.size) + +class AbstractResOpOrInputArg(AbstractValue, Typed): _attrs_ = ('_forwarded',) _forwarded = None # either another resop or OptInfo def get_forwarded(self): return self._forwarded + class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" @@ -109,6 +158,7 @@ boolreflex = -1 boolinverse = -1 vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement + casts = ('\x00', -1, '\x00', -1) def getopnum(self): return self.opnum @@ -192,7 +242,11 @@ except KeyError: num = len(memo) memo[self] = num - sres = self.type + str(num) + ' = ' + if self.is_vector(): + assert isinstance(self, VectorOp) + sres = 'v%d[%dx%s%d] = ' % (num, self.count, self.datatype, self.bytesize * 8) + else: + sres = self.type + str(num) + ' = ' #if self.result is not None: # sres = '%s = ' % (self.result,) else: @@ -219,6 +273,10 @@ except KeyError: num = len(memo) memo[self] = num + if self.is_vector(): + assert isinstance(self, VectorOp) + return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, + self.bytesize * 8) return self.type + str(num) def __repr__(self): @@ -363,6 +421,9 @@ def is_label(self): return self.getopnum() == rop.LABEL + def is_vector(self): + return self.vector == -2 + def returns_void(self): return self.type == 'v' @@ -376,28 +437,6 @@ class PlainResOp(AbstractResOp): pass -class CastResOp(AbstractResOp): - _attrs_ = ('casts') - casts = ('\x00', -1, '\x00', -1) - - def casts_box(self): - return True - - def cast_to(self): - _, _, to_type, size = self.casts - if self.casts[3] == 0: - if self.getopnum() == rop.INT_SIGNEXT: - from rpython.jit.metainterp.history import ConstInt - arg = self.getarg(1) - assert isinstance(arg, ConstInt) - return (to_type,arg.value) - else: - raise NotImplementedError - return (to_type,size) - - def cast_from(self): - return ('\x00',-1) - class ResOpWithDescr(AbstractResOp): _descr = None @@ -556,68 +595,56 @@ def accumulates_value(self): return True +class CastOp(object): + _mixin_ = True + + def casts_box(self): + return True + + def cast_to(self): + _, _, to_type, size = self.casts + if self.casts[3] == 0: + if self.getopnum() == rop.INT_SIGNEXT: + from rpython.jit.metainterp.history import ConstInt + arg = self.getarg(1) + assert isinstance(arg, ConstInt) + return (to_type,arg.value) + else: + raise NotImplementedError + return (to_type,size) + + def cast_from(self): + return ('\x00',-1) + class VectorOp(object): _mixin_ = True - #_attrs_ = ('item_type','item_count','item_size','item_signed','accum') - _attrs_ = ('item_type', 'item_count') - - #def __init__(self, item_type=FLOAT, item_count=2, item_size=8, item_signed=False, accum=None): - # assert item_type in (FLOAT, INT) - # self.item_type = item_type - # self.item_count = item_count - # self.item_size = item_size - # self.item_signed = item_signed - # self.accum = None - - def gettype(self): - return self.type - - def getbytes(self): - return self.slot_bytes - - def getcount(self): - return self.item_count - - def fully_packed(self, vec_reg_size): - return self.item_size * self.item_count == vec_reg_size - - def forget_value(self): - raise NotImplementedError("cannot forget value of vector") - - def clonebox(self): - return BoxVector(self.item_type, self.item_count, self.item_size, self.item_signed) - - def constbox(self): - raise NotImplementedError("not possible to have a constant vector box") - - def nonnull(self): - raise NotImplementedError("no value known, nonnull is unkown") + _attrs_ = ('count',) def repr_rpython(self): return repr_rpython(self, 'bv') def same_shape(self, other): - if not isinstance(other, BoxVector): + """ NOT_RPYTHON """ + if not other.is_vector(): return False # - if other.item_size == -1 or self.item_size == -1: + # TODO ? if other.item_size == -1 or self.item_size == -1: # fallback for tests that do not specify the size - return True + # return True # - if self.item_type != other.item_type: + if self.datatype != other.datatype: return False - if self.item_size != other.item_size: + if self.bytesize != other.bytesize: return False - if self.item_count != other.item_count: + if self.signed!= other.signed: return False - if self.item_signed != other.item_signed: + if self.count != other.count: return False return True def getaccum(self): return self.accum - class AbstractInputArg(AbstractResOpOrInputArg): def set_forwarded(self, forwarded_to): self._forwarded = forwarded_to @@ -642,6 +669,9 @@ def is_inputarg(self): return True + def initinputtype(self, cpu): + pass + class InputArgInt(IntOp, AbstractInputArg): def __init__(self, intval=0): self.setint(intval) @@ -974,11 +1004,11 @@ '_RAW_LOAD_FIRST', 'GETARRAYITEM_GC/2d/rfi', - 'VEC_GETARRAYITEM_GC/3d/fi', + 'VEC_GETARRAYITEM_GC/2d/fi', 'GETARRAYITEM_RAW/2d/fi', - 'VEC_GETARRAYITEM_RAW/3d/fi', + 'VEC_GETARRAYITEM_RAW/2d/fi', 'RAW_LOAD/2d/fi', - 'VEC_RAW_LOAD/3d/fi', + 'VEC_RAW_LOAD/2d/fi', '_RAW_LOAD_LAST', 'GETINTERIORFIELD_GC/2d/rfi', @@ -1059,19 +1089,15 @@ '_LAST', # for the backend to add more internal operations ] -FLOAT = 'f' -INT = 'i' _cast_ops = { - 'INT_SIGNEXT': (INT, 0, INT, 0), - 'CAST_FLOAT_TO_INT': (FLOAT, 8, INT, 4), - 'CAST_INT_TO_FLOAT': (INT, 4, FLOAT, 8), - 'CAST_FLOAT_TO_SINGLEFLOAT': (FLOAT, 8, FLOAT, 4), - 'CAST_SINGLEFLOAT_TO_FLOAT': (FLOAT, 4, FLOAT, 8), - 'CAST_PTR_TO_INT': (INT, 0, INT, 4), - 'CAST_INT_TO_PTR': (INT, 4, INT, 0), + 'INT_SIGNEXT': ('i', 0, 'i', 0), + 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4), + 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8), + 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4), + 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8), + 'CAST_PTR_TO_INT': ('r', 0, 'i', 4), + 'CAST_INT_TO_PTR': ('i', 4, 'r', 0), } -del FLOAT -del INT # ____________________________________________________________ @@ -1156,8 +1182,6 @@ if is_guard: assert withdescr baseclass = GuardResOp - elif name in _cast_ops: - baseclass = CastResOp elif withdescr: baseclass = ResOpWithDescr else: @@ -1171,6 +1195,8 @@ mixins.append(RefOp) else: assert result_type == 'n' + if name in _cast_ops: + mixins.append(CastOp) if name.startswith('VEC'): mixins.insert(1,VectorOp) From noreply at buildbot.pypy.org Mon Sep 14 14:20:21 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 14:20:21 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: I think I don't understand prebuilt instances in rpython but seems to work Message-ID: <20150914122021.C88D01C12D4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79623:58ad0b9810dc Date: 2015-09-14 14:20 +0200 http://bitbucket.org/pypy/pypy/changeset/58ad0b9810dc/ Log: I think I don't understand prebuilt instances in rpython but seems to work diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -738,6 +738,9 @@ metainterp.handle_guard_failure(self, deadframe) _trace_and_compile_from_bridge._dont_inline_ = True + def get_hash(self): + return self.status & self.ST_SHIFT_MASK + def must_compile(self, deadframe, metainterp_sd, jitdriver_sd): jitcounter = metainterp_sd.warmrunnerdesc.jitcounter # diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -1,12 +1,13 @@ import py -from rpython.rlib.jit import JitDriver, JitHookInterface, Counters +from rpython.rlib.jit import JitDriver, JitHookInterface, Counters, dont_look_inside from rpython.rlib import jit_hooks from rpython.jit.metainterp.test.support import LLJitMixin from rpython.jit.codewriter.policy import JitPolicy from rpython.jit.metainterp.resoperation import rop from rpython.rtyper.annlowlevel import hlstr, cast_instance_to_gcref from rpython.jit.metainterp.jitprof import Profiler, EmptyProfiler +from rpython.jit.codewriter.policy import JitPolicy class JitHookInterfaceTests(object): @@ -226,6 +227,58 @@ self.meta_interp(main, [1, 1], inline=True) self.check_resops(call_assembler_n=8) + def test_trace_next_iteration_hash(self): + driver = JitDriver(greens = ['s'], reds = ['i'], name="name") + class Hashes(object): + check = False + + def __init__(self): + self.l = [] + self.t = [] + + hashes = Hashes() + + class Hooks(object): + def before_compile(self, debug_info): + pass + + def after_compile(self, debug_info): + for op in debug_info.operations: + if op.is_guard(): + hashes.l.append(op.getdescr().get_hash()) + + def before_compile_bridge(self, debug_info): + pass + + def after_compile_bridge(self, debug_info): + hashes.t.append(debug_info.fail_descr.get_hash()) + + hooks = Hooks() + + @dont_look_inside + def foo(): + if hashes.l: + for item in hashes.l: + jit_hooks.trace_next_iteration_hash("name", item) + + def loop(i, s): + while i > 0: + driver.jit_merge_point(s=s, i=i) + foo() + if i == 3: + i -= 1 + i -= 1 + + def main(s, check): + hashes.check = check + loop(10, s) + + self.meta_interp(main, [1, 0], policy=JitPolicy(hooks)) + assert len(hashes.l) == 4 + assert len(hashes.t) == 0 + self.meta_interp(main, [1, 1], policy=JitPolicy(hooks)) + assert len(hashes.t) == 1 + class LLJitHookInterfaceTests(JitHookInterfaceTests): # use this for any backend, instead of the super class diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -618,7 +618,7 @@ jitdrivers_by_name[name] = jd m = _find_jit_markers(self.translator.graphs, ('get_jitcell_at_key', 'trace_next_iteration', - 'dont_trace_here')) + 'dont_trace_here', 'trace_next_iteration_hash')) accessors = {} def get_accessor(name, jitdriver_name, function, ARGS, green_arg_spec): @@ -663,6 +663,8 @@ func = JitCell.get_jitcell elif op.args[0].value == 'dont_trace_here': func = JitCell.dont_trace_here + elif op.args[0].value == 'trace_next_iteration_hash': + func = JitCell.trace_next_iteration_hash else: func = JitCell._trace_next_iteration argspec = jitdrivers_by_name[jitdriver_name]._green_args_spec diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -553,6 +553,10 @@ jitcounter.change_current_fraction(hash, 0.98) @staticmethod + def trace_next_iteration_hash(hash): + jitcounter.change_current_fraction(hash, 0.98) + + @staticmethod def ensure_jit_cell_at_key(greenkey): greenargs = unwrap_greenkey(greenkey) return JitCell._ensure_jit_cell_at_key(*greenargs) diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -157,3 +157,4 @@ get_jitcell_at_key = _new_hook('get_jitcell_at_key', SomePtr(llmemory.GCREF)) trace_next_iteration = _new_hook('trace_next_iteration', None) dont_trace_here = _new_hook('dont_trace_here', None) +trace_next_iteration_hash = _new_hook('trace_next_iteration_hash', None) From noreply at buildbot.pypy.org Mon Sep 14 14:28:15 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 14:28:15 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: a bit untested but try to expose minimal thing Message-ID: <20150914122815.485C41C130D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79624:da93da5c1b8f Date: 2015-09-14 14:28 +0200 http://bitbucket.org/pypy/pypy/changeset/da93da5c1b8f/ Log: a bit untested but try to expose minimal thing diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,9 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy + from pypy.module.pypyjit.interp_jit import pypy_hooks #from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy()#pypy_hooks) + return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -11,6 +11,7 @@ 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', 'dont_trace_here': 'interp_jit.dont_trace_here', 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'set_compile_bridge': 'interp_jit.set_compile_bridge', #'set_compile_hook': 'interp_resop.set_compile_hook', #'set_optimize_hook': 'interp_resop.set_optimize_hook', #'set_abort_hook': 'interp_resop.set_abort_hook', diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -6,7 +6,8 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside from rpython.rlib import jit, jit_hooks -from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rlib.jit import current_trace_length, unroll_parameters,\ + JitHookInterface from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt @@ -213,3 +214,77 @@ jit_hooks.trace_next_iteration( 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) return space.w_None + + at unwrap_spec(hash=r_uint) + at dont_look_inside +def trace_next_iteration_hash(space, hash): + jit_hooks.trace_next_iteration_hash(hash) + return space.w_None + +class Cache(object): + in_recursion = False + + def __init__(self, space): + self.w_compile_bridge = None + self.w_compile_loop = None + +def set_compile_bridge(space, w_hook): + cache = space.fromcache(Cache) + assert w_hook is not None + cache.w_compile_bridge = w_hook + +def set_compile_loop(space, w_hook): + from rpython.rlib.nonconst import NonConstant + + cache = space.fromcache(Cache) + assert w_hook is not None + cache.w_compile_loop = w_hook + cache.in_recursion = NonConstant(False) + +class PyPyJitHookInterface(JitHookInterface): + def after_compile(self, debug_info): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + l_w = [] + if not space.is_true(cache.w_compile_loop): + return + for i, op in enumerate(debug_info.operations): + if op.is_guard(): + w_t = space.newtuple([space.wrap(i), space.wrap(op.get_hash())]) + l_w.append(w_t) + try: + cache.in_recursion = True + try: + space.call_function(cache.w_compile_loop, space.newlist(l_w)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) + finally: + cache.in_recursion = False + + def after_compile_bridge(self, debug_info): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if not space.is_true(cache.w_compile_bridge): + return + w_hash = space.wrap(debug_info.fail_descr.get_hash()) + try: + cache.in_recursion = True + try: + space.call_function(cache.w_compile_bridge, w_hash) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) + finally: + cache.in_recursion = False + + def before_compile(self, debug_info): + pass + + def before_compile_bridge(self, debug_info): + pass + +pypy_hooks = PyPyJitHookInterface() + From noreply at buildbot.pypy.org Mon Sep 14 14:29:01 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 14:29:01 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: a bit more advanced Message-ID: <20150914122901.9F8561C130D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79625:5b5ad3a216ec Date: 2015-09-14 14:29 +0200 http://bitbucket.org/pypy/pypy/changeset/5b5ad3a216ec/ Log: a bit more advanced diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -252,7 +252,7 @@ return for i, op in enumerate(debug_info.operations): if op.is_guard(): - w_t = space.newtuple([space.wrap(i), space.wrap(op.get_hash())]) + w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.get_hash())]) l_w.append(w_t) try: cache.in_recursion = True From noreply at buildbot.pypy.org Mon Sep 14 14:43:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 14:43:08 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: oops Message-ID: <20150914124309.090F41C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79626:a527622dbab9 Date: 2015-09-14 14:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a527622dbab9/ Log: oops diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -28,7 +28,7 @@ def setup_after_space_initialization(self): # force the __extend__ hacks to occur early from pypy.module.pypyjit.interp_jit import pypyjitdriver - from pypy.module.pypyjit.hooks import pypy_hooks + from pypy.module.pypyjit.interp_jit import pypy_hooks # add the 'defaults' attribute from rpython.rlib.jit import PARAMETERS space = self.space From noreply at buildbot.pypy.org Mon Sep 14 15:01:16 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 15:01:16 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: one more forgotten attr Message-ID: <20150914130116.4AC1F1C0F85@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79627:8de46e159425 Date: 2015-09-14 15:01 +0200 http://bitbucket.org/pypy/pypy/changeset/8de46e159425/ Log: one more forgotten attr diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -12,6 +12,7 @@ 'dont_trace_here': 'interp_jit.dont_trace_here', 'trace_next_iteration': 'interp_jit.trace_next_iteration', 'set_compile_bridge': 'interp_jit.set_compile_bridge', + 'set_compile_loop': 'interp_jit.set_compile_loop', #'set_compile_hook': 'interp_resop.set_compile_hook', #'set_optimize_hook': 'interp_resop.set_optimize_hook', #'set_abort_hook': 'interp_resop.set_abort_hook', From noreply at buildbot.pypy.org Mon Sep 14 15:31:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 15:31:14 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: fix Message-ID: <20150914133114.6FBE71C0F85@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79628:b9514a2b467d Date: 2015-09-14 15:31 +0200 http://bitbucket.org/pypy/pypy/changeset/b9514a2b467d/ Log: fix diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -225,8 +225,8 @@ in_recursion = False def __init__(self, space): - self.w_compile_bridge = None - self.w_compile_loop = None + self.w_compile_bridge = space.w_None + self.w_compile_loop = space.w_None def set_compile_bridge(space, w_hook): cache = space.fromcache(Cache) From noreply at buildbot.pypy.org Mon Sep 14 15:37:27 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 15:37:27 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: make sure we call the correct method Message-ID: <20150914133727.68A4F1C0F85@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79629:7f56502060bf Date: 2015-09-14 15:37 +0200 http://bitbucket.org/pypy/pypy/changeset/7f56502060bf/ Log: make sure we call the correct method diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -252,7 +252,7 @@ return for i, op in enumerate(debug_info.operations): if op.is_guard(): - w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.get_hash())]) + w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) l_w.append(w_t) try: cache.in_recursion = True diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -738,7 +738,7 @@ metainterp.handle_guard_failure(self, deadframe) _trace_and_compile_from_bridge._dont_inline_ = True - def get_hash(self): + def get_jitcounter_hash(self): return self.status & self.ST_SHIFT_MASK def must_compile(self, deadframe, metainterp_sd, jitdriver_sd): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -245,13 +245,13 @@ def after_compile(self, debug_info): for op in debug_info.operations: if op.is_guard(): - hashes.l.append(op.getdescr().get_hash()) + hashes.l.append(op.getdescr().get_jitcounter_hash()) def before_compile_bridge(self, debug_info): pass def after_compile_bridge(self, debug_info): - hashes.t.append(debug_info.fail_descr.get_hash()) + hashes.t.append(debug_info.fail_descr.get_jitcounter_hash()) hooks = Hooks() From noreply at buildbot.pypy.org Mon Sep 14 15:41:21 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 15:41:21 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: one forgotten function Message-ID: <20150914134121.077681C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79630:03584b1bbcb0 Date: 2015-09-14 15:41 +0200 http://bitbucket.org/pypy/pypy/changeset/03584b1bbcb0/ Log: one forgotten function diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -11,6 +11,7 @@ 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', 'dont_trace_here': 'interp_jit.dont_trace_here', 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', 'set_compile_bridge': 'interp_jit.set_compile_bridge', 'set_compile_loop': 'interp_jit.set_compile_loop', #'set_compile_hook': 'interp_resop.set_compile_hook', From noreply at buildbot.pypy.org Mon Sep 14 15:54:06 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 15:54:06 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: oops Message-ID: <20150914135406.3F3721C12D4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79631:19f1c8229583 Date: 2015-09-14 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/19f1c8229583/ Log: oops diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -218,7 +218,7 @@ @unwrap_spec(hash=r_uint) @dont_look_inside def trace_next_iteration_hash(space, hash): - jit_hooks.trace_next_iteration_hash(hash) + jit_hooks.trace_next_iteration_hash('pypyjit', hash) return space.w_None class Cache(object): From noreply at buildbot.pypy.org Mon Sep 14 16:13:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 16:13:08 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: fix Message-ID: <20150914141308.8C91C1C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79632:d126d19fa016 Date: 2015-09-14 16:13 +0200 http://bitbucket.org/pypy/pypy/changeset/d126d19fa016/ Log: fix diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -642,6 +642,12 @@ return cast_instance_to_gcref(function(%s)) """ % (arg_spec, convert, arg_spec)).compile() in d FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) + elif name == "trace_next_iteration_hash": + exec py.code.Source(""" + def accessor(arg0): + function(arg0) + """) + FUNC = lltype.Ptr(lltype.FuncType(lltype.Unsigned, lltype.Void)) else: exec py.code.Source(""" def accessor(%s): From noreply at buildbot.pypy.org Mon Sep 14 16:15:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 16:15:08 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: fix Message-ID: <20150914141508.7F50E1C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79633:c2b89d981ec5 Date: 2015-09-14 16:14 +0200 http://bitbucket.org/pypy/pypy/changeset/c2b89d981ec5/ Log: fix diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -646,7 +646,7 @@ exec py.code.Source(""" def accessor(arg0): function(arg0) - """) + """).compile() in d FUNC = lltype.Ptr(lltype.FuncType(lltype.Unsigned, lltype.Void)) else: exec py.code.Source(""" From noreply at buildbot.pypy.org Mon Sep 14 16:19:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 16:19:43 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: a test and a fix Message-ID: <20150914141943.232121C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79634:3d7fa664b255 Date: 2015-09-14 16:19 +0200 http://bitbucket.org/pypy/pypy/changeset/3d7fa664b255/ Log: a test and a fix 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 @@ -598,7 +598,8 @@ descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) descr.copy_all_attributes_from(last_guard_op.getdescr()) guard_op.setdescr(descr) - guard_op.setfailargs(last_guard_op.getfailargs()) + descr.store_final_boxes(guard_op, last_guard_op.getfailargs(), + self.metainterp_sd) if guard_op.getopnum() == rop.GUARD_VALUE: guard_op = self._maybe_replace_guard_value(guard_op, descr) return guard_op diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1069,6 +1069,26 @@ res = self.meta_interp(run, [42], backendopt=True) assert res == 420 + def test_not_too_many_bridges(self): + jitdriver = JitDriver(greens = [], reds = 'auto') + + def f(i): + s = 0 + while i > 0: + jitdriver.jit_merge_point() + if i % 2 == 0: + s += 1 + elif i % 3 == 0: + s += 1 + elif i % 5 == 0: + s += 1 + elif i % 7 == 0: + s += 1 + i -= 1 + return s + + self.meta_interp(f, [30]) + self.check_trace_count(4) class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Mon Sep 14 16:22:18 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 16:22:18 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: fix Message-ID: <20150914142218.D590D1C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79635:56e54e53dcfe Date: 2015-09-14 16:22 +0200 http://bitbucket.org/pypy/pypy/changeset/56e54e53dcfe/ Log: fix diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -647,7 +647,8 @@ def accessor(arg0): function(arg0) """).compile() in d - FUNC = lltype.Ptr(lltype.FuncType(lltype.Unsigned, lltype.Void)) + FUNC = lltype.Ptr(lltype.FuncType([lltype.Unsigned], + lltype.Void)) else: exec py.code.Source(""" def accessor(%s): From noreply at buildbot.pypy.org Mon Sep 14 16:31:47 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 14 Sep 2015 16:31:47 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: typo Message-ID: <20150914143147.71F7C1C0797@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79636:807adc80ed23 Date: 2015-09-14 16:31 +0200 http://bitbucket.org/pypy/pypy/changeset/807adc80ed23/ Log: typo diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -270,7 +270,7 @@ return if not space.is_true(cache.w_compile_bridge): return - w_hash = space.wrap(debug_info.fail_descr.get_hash()) + w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) try: cache.in_recursion = True try: From noreply at buildbot.pypy.org Mon Sep 14 19:21:04 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 14 Sep 2015 19:21:04 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: further poking the scheduler. resoperations are now fully typed. this makes all the transformation logic much easier and less code, first simple tests pass already Message-ID: <20150914172105.07DB01C12D4@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79637:86dbbde6b191 Date: 2015-09-14 19:21 +0200 http://bitbucket.org/pypy/pypy/changeset/86dbbde6b191/ Log: further poking the scheduler. resoperations are now fully typed. this makes all the transformation logic much easier and less code, first simple tests pass already diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -97,7 +97,6 @@ """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) - import pdb; pdb.set_trace() while state.has_more(): node = self.next(state) if node: @@ -273,6 +272,37 @@ # return self.count + +class TypeOutput(object): + def __init__(self, type, count): + self.type = type + self.count = count + + + def bytecount(self): + return self.count * self.type.bytecount() + +class DataTyper(object): + + def infer_type(self, op): + # default action, pass through: find the first arg + # the output is the same as the first argument! + if op.returns_void() or op.argcount() == 0: + return + arg0 = op.getarg(0) + op.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + +class PassFirstArg(TypeOutput): + def __init__(self): + pass + +def update_arg_in_vector_pos(state, argidx, box): + arguments = [op.getoperation().getarg(argidx) for op in self.getoperations()] + for i,arg in enumerate(arguments): + #if i >= box.count: + # break + state.setvector_of_box(arg, i, box) + class TypeRestrict(object): ANY_TYPE = -1 ANY_SIZE = -1 @@ -296,389 +326,433 @@ return True -class TypeOutput(object): - def __init__(self, type, count): - self.type = type - self.count = count +class trans(object): + #DT_PASS = DataTyper() + TR_ANY = TypeRestrict() + TR_ANY_FLOAT = TypeRestrict(FLOAT) + TR_ANY_INTEGER = TypeRestrict(INT) + TR_FLOAT_2 = TypeRestrict(FLOAT, 4, 2) + TR_DOUBLE_2 = TypeRestrict(FLOAT, 8, 2) + TR_LONG = TypeRestrict(INT, 8, 2) + TR_INT_2 = TypeRestrict(INT, 4, 2) - def bytecount(self): - return self.count * self.type.bytecount() + #INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), DT_PASS) + #FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), DT_PASS) + #FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), DT_PASS) + #LOAD = LoadToVectorLoad() + #STORE = StoreToVectorStore() + #GUARD = PassThroughOp((TR_ANY_INTEGER,)) -class DataTyper(object): + # note that the following definition is x86 arch specific + MAPPING = { + rop.VEC_INT_ADD: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_SUB: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_MUL: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_AND: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_OR: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_XOR: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_EQ: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_NE: [TR_ANY_INTEGER, TR_ANY_INTEGER], - def infer_type(self, op): - # default action, pass through: find the first arg - # the output is the same as the first argument! - if op.returns_void() or op.argcount() == 0: - return - arg0 = op.getarg(0) - op.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + rop.VEC_FLOAT_ADD: [TR_ANY_FLOAT, TR_ANY_FLOAT], + rop.VEC_FLOAT_SUB: [TR_ANY_FLOAT, TR_ANY_FLOAT], + rop.VEC_FLOAT_MUL: [TR_ANY_FLOAT, TR_ANY_FLOAT], + rop.VEC_FLOAT_TRUEDIV: [TR_ANY_FLOAT, TR_ANY_FLOAT], + rop.VEC_FLOAT_ABS: [TR_ANY_FLOAT], + rop.VEC_FLOAT_NEG: [TR_ANY_FLOAT], -class PassFirstArg(TypeOutput): - def __init__(self): - pass + rop.VEC_RAW_LOAD_I: [None, None, TR_ANY], + rop.VEC_RAW_LOAD_F: [None, None, TR_ANY], + rop.VEC_GETARRAYITEM_RAW_I: [None, None, TR_ANY], + rop.VEC_GETARRAYITEM_RAW_F: [None, None, TR_ANY], + rop.VEC_GETARRAYITEM_GC_I: [None, None, TR_ANY], + rop.VEC_GETARRAYITEM_GC_F: [None, None, TR_ANY], + + rop.VEC_RAW_STORE: [None, None, None, TR_ANY], + rop.VEC_SETARRAYITEM_RAW: [None, None, None, TR_ANY], + rop.VEC_SETARRAYITEM_GC: [None, None, None, TR_ANY], + + rop.GUARD_TRUE: [TR_ANY_INTEGER], + rop.GUARD_FALSE: [TR_ANY_INTEGER], + + ## irregular + rop.VEC_INT_SIGNEXT: [TR_ANY_INTEGER], + + rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: [TR_DOUBLE_2], + rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: [TR_FLOAT_2], + rop.VEC_CAST_FLOAT_TO_INT: [TR_DOUBLE_2], + rop.VEC_CAST_INT_TO_FLOAT: [TR_INT_2], + + rop.VEC_FLOAT_EQ: [TR_ANY_FLOAT,TR_ANY_FLOAT], + rop.VEC_FLOAT_NE: [TR_ANY_FLOAT,TR_ANY_FLOAT], + rop.VEC_INT_IS_TRUE: [TR_ANY_INTEGER,TR_ANY_INTEGER], + } + + # TODO? + UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, + rop.UINT_LT, rop.UINT_LE, + rop.UINT_GT, rop.UINT_GE) + +def turn_to_vector(state, pack): + """ Turn a pack into a vector instruction """ + # + # TODO self.check_if_pack_supported(pack) + op = pack.leftmost() + args = op.getarglist() + prepare_arguments(state, pack, args) + vop = VecOperation(op.vector, args, op, pack.numops(), op.getdescr()) + for i,node in enumerate(pack.operations): + op = node.getoperation() + state.setvector_of_box(op,i,vop) + # + if op.is_guard(): + assert isinstance(op, GuardResOp) + assert isinstance(vop, GuardResOp) + vop.setfailargs(op.getfailargs()) + vop.rd_snapshot = op.rd_snapshot + state.costmodel.record_pack_savings(pack, pack.numops()) + # + if pack.is_accumulating(): + box = oplist[position].result + assert box is not None + for node in pack.operations: + op = node.getoperation() + assert not op.returns_void() + state.renamer.start_renaming(op, box) + # + state.oplist.append(vop) + + +def prepare_arguments(state, pack, args): + # Transforming one argument to a vector box argument + # The following cases can occur: + # 1) argument is present in the box_to_vbox map. + # a) vector can be reused immediatly (simple case) + # b) an operation forces the unpacking of a vector + # 2) argument is not known to reside in a vector + # a) expand vars/consts before the label and add as argument + # b) expand vars created in the loop body + # + restrictions = trans.MAPPING[pack.leftmost().vector] + for i,arg in enumerate(args): + if i >= len(restrictions) or restrictions[i] is None: + # ignore this argument + continue + print "trans", i, "arg", arg + if arg.returns_vector(): + continue + pos, vecop = state.getvector_of_box(arg) + if not vecop: + # 2) constant/variable expand this box + # TODO just as one function call + vecop = self.expand(arg, i) + state.setvector_of_box(arg, 0, vecop) + pos = 0 + continue + args[i] = vecop + assemble_scattered_values(state, pack, args, i) + position_values(state, pack, args, i, arg, pos) + +def assemble_scattered_values(state, pack, args, index): + vectors = pack.argument_vectors(state, pack, index) + if len(vectors) > 1: + # the argument is scattered along different vector boxes + value = gather(vectors, packable) + update_arg_in_vector_pos(state, i, value) + args[i] = value + #if packed < packable and len(vboxes) > 1: + # # the argument is scattered along different vector boxes + # args[i] = self.gather(vboxes, packable) + # self.update_arg_in_vector_pos(i, args[i]) + # continue + +def gather(self, vboxes, target_count): # packed < packable and packed < stride: + (_, box) = vboxes[0] + i = 1 + while i < len(vboxes): + (box2_pos, box2) = vboxes[i] + if box.getcount() + box2.getcount() <= target_count: + box = self.package(box, box.getcount(), + box2, box2_pos, box2.getcount()) + i += 1 + return box + +def position_values(state, pack, args, index, arg, pos): + pass + #if pos != 0: + # # The vector box is at a position != 0 but it + # # is required to be at position 0. Unpack it! + # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) + # self.update_arg_in_vector_pos(i, args[i]) + # continue + + # convert size i64 -> i32, i32 -> i64, ... + # TODO if self.bytesize > 0: + # determine_trans( + # self.input_type.getsize() != vecop.getsize(): + # vecop = self.extend(vecop, self.input_type) + + # use the input as an indicator for the pack type + #packable = vecop.maximum_numops() + #packed = vecop.count + #assert packed >= 0 + #assert packable >= 0 + #if packed > packable: + # # the argument has more items than the operation is able to process! + # # pos == 0 then it is already at the right place + # if pos != 0: + # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) + # self.update_arg_in_vector_pos(i, args[i]) + # #self.update_input_output(self.pack) + # continue + # else: + # assert vecop is not None + # args[i] = vecop + # continue + #vboxes = self.vector_boxes_for_args(i) + #if packed < packable and len(vboxes) > 1: + # # the argument is scattered along different vector boxes + # args[i] = self.gather(vboxes, packable) + # self.update_arg_in_vector_pos(i, args[i]) + # continue + #if pos != 0: + # # The vector box is at a position != 0 but it + # # is required to be at position 0. Unpack it! + # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) + # self.update_arg_in_vector_pos(i, args[i]) + # continue + ## + #assert vecop is not None + #args[i] = vecop + +def before_argument_transform(self, args): + pass + +def check_if_pack_supported(self, pack): + op0 = pack.operations[0].getoperation() + if self.input_type is None: + # must be a load/guard op + return + insize = self.input_type.getsize() + if op0.is_typecast(): + # prohibit the packing of signext calls that + # cast to int16/int8. + _, outsize = op0.cast_to() + self.sched_data._prevent_signext(outsize, insize) + if op0.getopnum() == rop.INT_MUL: + if insize == 8 or insize == 1: + # see assembler for comment why + raise NotAProfitableLoop + +#def transform_result(self, result): +# if result is None: +# return None +# vbox = self.new_result_vector_box() +# # +# # mark the position and the vbox in the hash +# for i, node in enumerate(self.getoperations()): +# if i >= vbox.getcount(): +# break +# op = node.getoperation() +# self.sched_data.setvector_of_box(op, i, vbox) +# return vbox + +#def new_result_vector_box(self): +# type = self.output_type.gettype() +# size = self.output_type.getsize() +# count = min(self.output_type.getcount(), len(self.pack.operations)) +# signed = self.output_type.signed +# return BoxVector(type, count, size, signed) + +#def getoperations(self): +# return self.pack.operations + +#def transform_arguments(self, args): +# """ Transforming one argument to a vector box argument +# The following cases can occur: +# 1) argument is present in the box_to_vbox map. +# a) vector can be reused immediatly (simple case) +# b) vector is to big +# c) vector is to small +# 2) argument is not known to reside in a vector +# a) expand vars/consts before the label and add as argument +# b) expand vars created in the loop body +# """ +# for i,arg in enumerate(args): +# if arg.returns_vector(): +# continue +# if not self.is_vector_arg(i): +# continue +# box_pos, vbox = self.sched_data.getvector_of_box(arg) +# if not vbox: +# # constant/variable expand this box +# vbox = self.expand(arg, i) +# self.sched_data.setvector_of_box(arg, 0, vbox) +# box_pos = 0 +# # convert size i64 -> i32, i32 -> i64, ... +# if self.input_type.getsize() > 0 and \ +# self.input_type.getsize() != vbox.getsize(): +# vbox = self.extend(vbox, self.input_type) + +# # use the input as an indicator for the pack type +# packable = self.input_type.getcount() +# packed = vbox.getcount() +# assert packed >= 0 +# assert packable >= 0 +# if packed > packable: +# # the argument has more items than the operation is able to process! +# # box_pos == 0 then it is already at the right place +# if box_pos != 0: +# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) +# self.update_arg_in_vector_pos(i, args[i]) +# #self.update_input_output(self.pack) +# continue +# else: +# assert vbox is not None +# args[i] = vbox +# continue +# vboxes = self.vector_boxes_for_args(i) +# if packed < packable and len(vboxes) > 1: +# # the argument is scattered along different vector boxes +# args[i] = self.gather(vboxes, packable) +# self.update_arg_in_vector_pos(i, args[i]) +# continue +# if box_pos != 0: +# # The vector box is at a position != 0 but it +# # is required to be at position 0. Unpack it! +# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) +# self.update_arg_in_vector_pos(i, args[i]) +# continue +# #self.update_input_output(self.pack) +# # +# assert vbox is not None +# args[i] = vbox + +def extend(self, vbox, newtype): + assert vbox.gettype() == newtype.gettype() + if vbox.gettype() == INT: + return self.extend_int(vbox, newtype) + else: + raise NotImplementedError("cannot yet extend float") + +def extend_int(self, vbox, newtype): + vbox_cloned = newtype.new_vector_box(vbox.getcount()) + self.sched_data._prevent_signext(newtype.getsize(), vbox.getsize()) + newsize = newtype.getsize() + assert newsize > 0 + op = ResOperation(rop.VEC_INT_SIGNEXT, + [vbox, ConstInt(newsize)], + vbox_cloned) + self.costmodel.record_cast_int(vbox.getsize(), newtype.getsize(), vbox.getcount()) + self.vecops.append(op) + return vbox_cloned + +def unpack(self, vbox, index, count, arg_ptype): + """ Extract parts of the vector box into another vector box """ + assert index < vbox.getcount() + assert index + count <= vbox.getcount() + assert count > 0 + vbox_cloned = vectorbox_clone_set(vbox, count=count) + opnum = getunpackopnum(vbox.gettype()) + op = ResOperation(opnum, [vbox, ConstInt(index), ConstInt(count)], vbox_cloned) + self.costmodel.record_vector_unpack(vbox, index, count) + self.vecops.append(op) + # + return vbox_cloned + +def package(self, tgt, tidx, src, sidx, scount): + """ tgt = [1,2,3,4,_,_,_,_] + src = [5,6,_,_] + new_box = [1,2,3,4,5,6,_,_] after the operation, tidx=4, scount=2 + """ + assert sidx == 0 # restriction + count = tgt.getcount() + src.getcount() + new_box = vectorbox_clone_set(tgt, count=count) + opnum = getpackopnum(tgt.gettype()) + op = ResOperation(opnum, [tgt, src, ConstInt(tidx), ConstInt(scount)], new_box) + self.vecops.append(op) + self.costmodel.record_vector_pack(src, sidx, scount) + if not we_are_translated(): + self._check_vec_pack(op) + return new_box + +def _check_vec_pack(self, op): + result = op + arg0 = op.getarg(0) + arg1 = op.getarg(1) + index = op.getarg(2) + count = op.getarg(3) + assert isinstance(result, BoxVector) + assert isinstance(arg0, BoxVector) + assert isinstance(index, ConstInt) + assert isinstance(count, ConstInt) + assert arg0.getsize() == result.getsize() + if isinstance(arg1, BoxVector): + assert arg1.getsize() == result.getsize() + else: + assert count.value == 1 + assert index.value < result.getcount() + assert index.value + count.value <= result.getcount() + assert result.getcount() > arg0.getcount() + +def expand(self, arg, argidx): + """ Expand a value into a vector box. useful for arith metic + of one vector with a scalar (either constant/varialbe) + """ + elem_count = self.input_type.getcount() + vbox = self.input_type.new_vector_box(elem_count) + box_type = arg.type + expanded_map = self.sched_data.expanded_map + # note that heterogenous nodes are not yet tracked + already_expanded = expanded_map.get(arg, None) + if already_expanded: + return already_expanded + + ops = self.sched_data.invariant_oplist + variables = self.sched_data.invariant_vector_vars + if isinstance(arg,Box) and arg not in self.sched_data.inputargs: + ops = self.vecops + variables = None + if isinstance(arg, BoxVector): + box_type = arg.gettype() + + for i, node in enumerate(self.getoperations()): + op = node.getoperation() + if not arg.same_box(op.getarg(argidx)): + break + i += 1 + else: + expand_opnum = getexpandopnum(box_type) + op = ResOperation(expand_opnum, [arg, ConstInt(vbox.item_count)], vbox) + ops.append(op) + if variables is not None: + variables.append(vbox) + expanded_map[arg] = vbox + return vbox + + op = ResOperation(rop.VEC_BOX, [ConstInt(elem_count)], vbox) + ops.append(op) + opnum = getpackopnum(arg.type) + for i,node in enumerate(self.getoperations()): + op = node.getoperation() + arg = op.getarg(argidx) + new_box = vbox.clonebox() + ci = ConstInt(i) + c1 = ConstInt(1) + op = ResOperation(opnum, [vbox,arg,ci,c1], new_box) + vbox = new_box + ops.append(op) + + if variables is not None: + variables.append(vbox) + return vbox class OpToVectorOp(object): - def __init__(self, restrictargs, typeoutput): - self.args = list(restrictargs) # do not use a tuple. rpython cannot union - self.out = typeoutput - - def as_vector_operation(self, state, pack): - # - # TODO self.check_if_pack_supported(pack) - op = pack.leftmost() - args = op.getarglist() - self.prepare_arguments(state, op.getarglist()) - vop = VecOperation(op.vector, args, op, pack.numops(), op.getdescr()) - # - if op.is_guard(): - assert isinstance(op, GuardResOp) - assert isinstance(vop, GuardResOp) - vop.setfailargs(op.getfailargs()) - vop.rd_snapshot = op.rd_snapshot - state.costmodel.record_pack_savings(pack, pack.numops()) - # - if pack.is_accumulating(): - box = oplist[position].result - assert box is not None - for node in pack.operations: - op = node.getoperation() - assert not op.returns_void() - scheduler.renamer.start_renaming(op, box) - # - state.oplist.append(vop) - - def prepare_arguments(self, state, args): - self.before_argument_transform(args) - # Transforming one argument to a vector box argument - # The following cases can occur: - # 1) argument is present in the box_to_vbox map. - # a) vector can be reused immediatly (simple case) - # b) vector is to big - # c) vector is to small - # 2) argument is not known to reside in a vector - # a) expand vars/consts before the label and add as argument - # b) expand vars created in the loop body - # - for i,arg in enumerate(args): - if arg.returns_vector(): - continue - if not self.transform_arg_at(i): - continue - box_pos, vbox = state.getvector_of_box(arg) - if not vbox: - # 2) constant/variable expand this box - vbox = self.expand(arg, i) - self.sched_data.setvector_of_box(arg, 0, vbox) - box_pos = 0 - # convert size i64 -> i32, i32 -> i64, ... - if self.input_type.getsize() > 0 and \ - self.input_type.getsize() != vbox.getsize(): - vbox = self.extend(vbox, self.input_type) - - # use the input as an indicator for the pack type - packable = self.input_type.getcount() - packed = vbox.getcount() - assert packed >= 0 - assert packable >= 0 - if packed > packable: - # the argument has more items than the operation is able to process! - # box_pos == 0 then it is already at the right place - if box_pos != 0: - args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) - self.update_arg_in_vector_pos(i, args[i]) - #self.update_input_output(self.pack) - continue - else: - assert vbox is not None - args[i] = vbox - continue - vboxes = self.vector_boxes_for_args(i) - if packed < packable and len(vboxes) > 1: - # the argument is scattered along different vector boxes - args[i] = self.gather(vboxes, packable) - self.update_arg_in_vector_pos(i, args[i]) - continue - if box_pos != 0: - # The vector box is at a position != 0 but it - # is required to be at position 0. Unpack it! - args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) - self.update_arg_in_vector_pos(i, args[i]) - continue - #self.update_input_output(self.pack) - # - assert vbox is not None - args[i] = vbox - - def before_argument_transform(self, args): + def __init__(self): #, restrictargs, typeoutput): pass - - def check_if_pack_supported(self, pack): - op0 = pack.operations[0].getoperation() - if self.input_type is None: - # must be a load/guard op - return - insize = self.input_type.getsize() - if op0.casts_box(): - # prohibit the packing of signext calls that - # cast to int16/int8. - _, outsize = op0.cast_to() - self.sched_data._prevent_signext(outsize, insize) - if op0.getopnum() == rop.INT_MUL: - if insize == 8 or insize == 1: - # see assembler for comment why - raise NotAProfitableLoop - - def transform_result(self, result): - if result is None: - return None - vbox = self.new_result_vector_box() - # - # mark the position and the vbox in the hash - for i, node in enumerate(self.getoperations()): - if i >= vbox.getcount(): - break - op = node.getoperation() - self.sched_data.setvector_of_box(op, i, vbox) - return vbox - - def new_result_vector_box(self): - type = self.output_type.gettype() - size = self.output_type.getsize() - count = min(self.output_type.getcount(), len(self.pack.operations)) - signed = self.output_type.signed - return BoxVector(type, count, size, signed) - - def getoperations(self): - return self.pack.operations - - def transform_arguments(self, args): - """ Transforming one argument to a vector box argument - The following cases can occur: - 1) argument is present in the box_to_vbox map. - a) vector can be reused immediatly (simple case) - b) vector is to big - c) vector is to small - 2) argument is not known to reside in a vector - a) expand vars/consts before the label and add as argument - b) expand vars created in the loop body - """ - for i,arg in enumerate(args): - if arg.returns_vector(): - continue - if not self.is_vector_arg(i): - continue - box_pos, vbox = self.sched_data.getvector_of_box(arg) - if not vbox: - # constant/variable expand this box - vbox = self.expand(arg, i) - self.sched_data.setvector_of_box(arg, 0, vbox) - box_pos = 0 - # convert size i64 -> i32, i32 -> i64, ... - if self.input_type.getsize() > 0 and \ - self.input_type.getsize() != vbox.getsize(): - vbox = self.extend(vbox, self.input_type) - - # use the input as an indicator for the pack type - packable = self.input_type.getcount() - packed = vbox.getcount() - assert packed >= 0 - assert packable >= 0 - if packed > packable: - # the argument has more items than the operation is able to process! - # box_pos == 0 then it is already at the right place - if box_pos != 0: - args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) - self.update_arg_in_vector_pos(i, args[i]) - #self.update_input_output(self.pack) - continue - else: - assert vbox is not None - args[i] = vbox - continue - vboxes = self.vector_boxes_for_args(i) - if packed < packable and len(vboxes) > 1: - # the argument is scattered along different vector boxes - args[i] = self.gather(vboxes, packable) - self.update_arg_in_vector_pos(i, args[i]) - continue - if box_pos != 0: - # The vector box is at a position != 0 but it - # is required to be at position 0. Unpack it! - args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) - self.update_arg_in_vector_pos(i, args[i]) - continue - #self.update_input_output(self.pack) - # - assert vbox is not None - args[i] = vbox - - def gather(self, vboxes, target_count): # packed < packable and packed < stride: - (_, box) = vboxes[0] - i = 1 - while i < len(vboxes): - (box2_pos, box2) = vboxes[i] - if box.getcount() + box2.getcount() <= target_count: - box = self.package(box, box.getcount(), - box2, box2_pos, box2.getcount()) - i += 1 - return box - - def update_arg_in_vector_pos(self, argidx, box): - arguments = [op.getoperation().getarg(argidx) for op in self.getoperations()] - for i,arg in enumerate(arguments): - if i >= box.getcount(): - break - self.sched_data.setvector_of_box(arg, i, box) - - def vector_boxes_for_args(self, index): - args = [op.getoperation().getarg(index) for op in self.getoperations()] - vboxes = [] - last_vbox = None - for arg in args: - pos, vbox = self.sched_data.getvector_of_box(arg) - if vbox is not last_vbox and vbox is not None: - vboxes.append((pos, vbox)) - last_vbox = vbox - return vboxes - - - def extend(self, vbox, newtype): - assert vbox.gettype() == newtype.gettype() - if vbox.gettype() == INT: - return self.extend_int(vbox, newtype) - else: - raise NotImplementedError("cannot yet extend float") - - def extend_int(self, vbox, newtype): - vbox_cloned = newtype.new_vector_box(vbox.getcount()) - self.sched_data._prevent_signext(newtype.getsize(), vbox.getsize()) - newsize = newtype.getsize() - assert newsize > 0 - op = ResOperation(rop.VEC_INT_SIGNEXT, - [vbox, ConstInt(newsize)], - vbox_cloned) - self.costmodel.record_cast_int(vbox.getsize(), newtype.getsize(), vbox.getcount()) - self.vecops.append(op) - return vbox_cloned - - def unpack(self, vbox, index, count, arg_ptype): - """ Extract parts of the vector box into another vector box """ - assert index < vbox.getcount() - assert index + count <= vbox.getcount() - assert count > 0 - vbox_cloned = vectorbox_clone_set(vbox, count=count) - opnum = getunpackopnum(vbox.gettype()) - op = ResOperation(opnum, [vbox, ConstInt(index), ConstInt(count)], vbox_cloned) - self.costmodel.record_vector_unpack(vbox, index, count) - self.vecops.append(op) - # - return vbox_cloned - - def package(self, tgt, tidx, src, sidx, scount): - """ tgt = [1,2,3,4,_,_,_,_] - src = [5,6,_,_] - new_box = [1,2,3,4,5,6,_,_] after the operation, tidx=4, scount=2 - """ - assert sidx == 0 # restriction - count = tgt.getcount() + src.getcount() - new_box = vectorbox_clone_set(tgt, count=count) - opnum = getpackopnum(tgt.gettype()) - op = ResOperation(opnum, [tgt, src, ConstInt(tidx), ConstInt(scount)], new_box) - self.vecops.append(op) - self.costmodel.record_vector_pack(src, sidx, scount) - if not we_are_translated(): - self._check_vec_pack(op) - return new_box - - def _check_vec_pack(self, op): - result = op - arg0 = op.getarg(0) - arg1 = op.getarg(1) - index = op.getarg(2) - count = op.getarg(3) - assert isinstance(result, BoxVector) - assert isinstance(arg0, BoxVector) - assert isinstance(index, ConstInt) - assert isinstance(count, ConstInt) - assert arg0.getsize() == result.getsize() - if isinstance(arg1, BoxVector): - assert arg1.getsize() == result.getsize() - else: - assert count.value == 1 - assert index.value < result.getcount() - assert index.value + count.value <= result.getcount() - assert result.getcount() > arg0.getcount() - - def expand(self, arg, argidx): - """ Expand a value into a vector box. useful for arith metic - of one vector with a scalar (either constant/varialbe) - """ - elem_count = self.input_type.getcount() - vbox = self.input_type.new_vector_box(elem_count) - box_type = arg.type - expanded_map = self.sched_data.expanded_map - # note that heterogenous nodes are not yet tracked - already_expanded = expanded_map.get(arg, None) - if already_expanded: - return already_expanded - - ops = self.sched_data.invariant_oplist - variables = self.sched_data.invariant_vector_vars - if isinstance(arg,Box) and arg not in self.sched_data.inputargs: - ops = self.vecops - variables = None - if isinstance(arg, BoxVector): - box_type = arg.gettype() - - for i, node in enumerate(self.getoperations()): - op = node.getoperation() - if not arg.same_box(op.getarg(argidx)): - break - i += 1 - else: - expand_opnum = getexpandopnum(box_type) - op = ResOperation(expand_opnum, [arg, ConstInt(vbox.item_count)], vbox) - ops.append(op) - if variables is not None: - variables.append(vbox) - expanded_map[arg] = vbox - return vbox - - op = ResOperation(rop.VEC_BOX, [ConstInt(elem_count)], vbox) - ops.append(op) - opnum = getpackopnum(arg.type) - for i,node in enumerate(self.getoperations()): - op = node.getoperation() - arg = op.getarg(argidx) - new_box = vbox.clonebox() - ci = ConstInt(i) - c1 = ConstInt(1) - op = ResOperation(opnum, [vbox,arg,ci,c1], new_box) - vbox = new_box - ops.append(op) - - if variables is not None: - variables.append(vbox) - return vbox - - def transform_arg_at(self, i): - if i < 0 or i >= len(self.args): - return False - return self.args[i] is not None - - def get_output_type_given(self, input_type, op): - return input_type - - def get_input_type_given(self, output_type, op): - return output_type - - def force_input(self, ptype): - """ Some operations require a specific count/size, - they can force the input type here! - """ - return ptype + #self.args = list(restrictargs) # do not use a tuple. rpython cannot union + #self.out = typeoutput class OpToVectorOpConv(OpToVectorOp): def __init__(self, intype, outtype): @@ -790,97 +864,31 @@ raise AssertionError("cannot infer input type from output type") -class trans(object): - DT_PASS = DataTyper() - TR_ANY_FLOAT = TypeRestrict(FLOAT) - TR_ANY_INTEGER = TypeRestrict(INT) - TR_FLOAT_2 = TypeRestrict(FLOAT, 4, 2) - TR_DOUBLE_2 = TypeRestrict(FLOAT, 8, 2) - TR_LONG = TypeRestrict(INT, 8, 2) - TR_INT_2 = TypeRestrict(INT, 4, 2) - - INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), DT_PASS) - FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), DT_PASS) - FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), DT_PASS) - LOAD = LoadToVectorLoad() - STORE = StoreToVectorStore() - GUARD = PassThroughOp((TR_ANY_INTEGER,)) - - # note that the following definition is x86 arch specific - MAPPING = { - rop.VEC_INT_ADD: INT, - rop.VEC_INT_SUB: INT, - rop.VEC_INT_MUL: INT, - rop.VEC_INT_AND: INT, - rop.VEC_INT_OR: INT, - rop.VEC_INT_XOR: INT, - rop.VEC_INT_EQ: INT, - rop.VEC_INT_NE: INT, - - rop.VEC_FLOAT_ADD: FLOAT, - rop.VEC_FLOAT_SUB: FLOAT, - rop.VEC_FLOAT_MUL: FLOAT, - rop.VEC_FLOAT_TRUEDIV: FLOAT, - rop.VEC_FLOAT_ABS: FLOAT_UNARY, - rop.VEC_FLOAT_NEG: FLOAT_UNARY, - - rop.VEC_RAW_LOAD_I: LOAD, - rop.VEC_RAW_LOAD_F: LOAD, - rop.VEC_GETARRAYITEM_RAW_I: LOAD, - rop.VEC_GETARRAYITEM_RAW_F: LOAD, - rop.VEC_GETARRAYITEM_GC_I: LOAD, - rop.VEC_GETARRAYITEM_GC_F: LOAD, - - rop.VEC_RAW_STORE: STORE, - rop.VEC_SETARRAYITEM_RAW: STORE, - rop.VEC_SETARRAYITEM_GC: STORE, - - rop.GUARD_TRUE: GUARD, - rop.GUARD_FALSE: GUARD, - - # irregular - rop.VEC_INT_SIGNEXT: SignExtToVectorOp((TR_ANY_INTEGER,), None), - - rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: OpToVectorOpConv(TR_DOUBLE_2, None), #RESTRICT_2_FLOAT), - rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: OpToVectorOpConv(TR_FLOAT_2, None), #RESTRICT_2_DOUBLE), - rop.VEC_CAST_FLOAT_TO_INT: OpToVectorOpConv(TR_DOUBLE_2, None), #RESTRICT_2_INT), - rop.VEC_CAST_INT_TO_FLOAT: OpToVectorOpConv(TR_INT_2, None), #RESTRICT_2_DOUBLE), - - rop.VEC_FLOAT_EQ: OpToVectorOp((TR_ANY_FLOAT,TR_ANY_FLOAT), None), - rop.VEC_FLOAT_NE: OpToVectorOp((TR_ANY_FLOAT,TR_ANY_FLOAT), None), - rop.VEC_INT_IS_TRUE: OpToVectorOp((TR_ANY_INTEGER,TR_ANY_INTEGER), None), # TR_ANY_INTEGER), - } - - # TODO? - UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, - rop.UINT_LT, rop.UINT_LE, - rop.UINT_GT, rop.UINT_GE) - -def determine_input_output_types(pack, node, forward): - """ This function is two fold. If moving forward, it - gets an input type from the packs output type and returns - the transformed packtype. - - Moving backward, the origins pack input type is the output - type and the transformation of the packtype (in reverse direction) - is the input - """ - op = node.getoperation() - op2vecop = determine_trans(op) - if forward: - input_type = op2vecop.force_input(pack.output_type) - output_type = op2vecop.get_output_type_given(input_type, op) - if output_type: - output_type = output_type.clone() - else: - # going backwards, things are not that easy anymore - output_type = pack.input_type - input_type = op2vecop.get_input_type_given(output_type, op) - if input_type: - input_type = input_type.clone() - - return input_type, output_type +#def determine_input_output_types(pack, node, forward): +# """ This function is two fold. If moving forward, it +# gets an input type from the packs output type and returns +# the transformed packtype. +# +# Moving backward, the origins pack input type is the output +# type and the transformation of the packtype (in reverse direction) +# is the input +# """ +# op = node.getoperation() +# op2vecop = determine_trans(op) +# if forward: +# input_type = op2vecop.force_input(pack.output_type) +# output_type = op2vecop.get_output_type_given(input_type, op) +# if output_type: +# output_type = output_type.clone() +# else: +# # going backwards, things are not that easy anymore +# output_type = pack.input_type +# input_type = op2vecop.get_input_type_given(output_type, op) +# if input_type: +# input_type = input_type.clone() +# +# return input_type, output_type def determine_trans(op): op2vecop = trans.MAPPING.get(op.vector, None) @@ -951,8 +959,8 @@ assert node.pack.numops() > 1 for node in node.pack.operations: scheduler.mark_emitted(node, self) - op2vecop = determine_trans(node.pack.leftmost()) - op2vecop.as_vector_operation(self, node.pack) + # TODO op2vecop = determine_trans(node.pack.leftmost()) + turn_to_vector(self, node.pack) return True return False @@ -1021,39 +1029,22 @@ def getvector_of_box(self, arg): return self.box_to_vbox.get(arg, (-1, None)) - def setvector_of_box(self, box, off, vector): - assert off < vector.getcount() - assert box.type != 'V' - self.box_to_vbox[box] = (off, vector) + def setvector_of_box(self, var, off, vector): + assert off < vector.count + assert not var.is_vector() + self.box_to_vbox[var] = (off, vector) def opcount_filling_vector_register(pack, vec_reg_size): """ how many operations of that kind can one execute with a machine instruction of register size X? """ - pack_type = pack.input_type - if pack_type is None: - pack_type = pack.output_type # load operations - op = pack.leftmost() - if op.casts_box(): - count = pack_type.getcount() - return count - count = vec_reg_size // pack_type.getsize() - return count - -def maximum_byte_size(pack, vec_reg_size): - """ The maxmum size in bytes the operation is able to - process with the hardware register and the operation - semantics. - """ - op = pack.leftmost() - if op.casts_box(): - # casting is special, often only takes a half full vector - pack_type = pack.input_type - if pack_type is None: - pack_type = pack.output_type # load operations - return pack_type.byte_size() - return vec_reg_size + if op.is_typecast(): + if op.casts_down(): + return vec_reg_size // op.cast_from_bytesize() + else: + return vec_reg_size // op.cast_to_bytesize() + return vec_reg_size // op.bytesize class Pack(object): """ A pack is a set of n statements that are: @@ -1080,6 +1071,9 @@ def leftmost(self): return self.operations[0].getoperation() + def rightmost(self): + return self.operations[-1].getoperation() + def pack_type(self): ptype = self.input_type if self.input_type is None: @@ -1113,14 +1107,15 @@ return 0 if self.numops() == 0: return -1 - size = maximum_byte_size(self, vec_reg_size) - return left.bytesize * self.numops() - size - #if self.input_type is None: - # e.g. load operations - # return self.output_type.bytecount(self) - size - # default only consider the input type - # e.g. store operations, int_add, ... - #return self.input_type.bytecount(self) - size + if left.is_typecast(): + # casting is special, often only takes a half full vector + if left.casts_down(): + # size is reduced + return left.cast_from_bytesize() * self.numops() - vec_reg_size + else: + # size is increased + return left.cast_to_bytesize() * self.numops() - vec_reg_size + return left.bytesize * self.numops() - vec_reg_size def is_full(self, vec_reg_size): """ If one input element times the opcount is equal @@ -1190,6 +1185,17 @@ accum = False return rightmost is leftmost and accum + def argument_vectors(self, state, pack, index): + args = [node.getoperation().getarg(index) for node in pack.operations] + vectors = [] + last = None + for arg in args: + pos, vecop = state.getvector_of_box(arg) + if vecop is not last and vecop is not None: + vectors.append((pos, vecop)) + last = vecop + return vectors + def __repr__(self): if len(self.operations) == 0: return "Pack(empty)" diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -50,7 +50,7 @@ else: label = loop.operations[0] label.setdescr(TargetToken(token)) - loop = VectorLoop(label, loop.operations[1:-1], loop.operations[-1]) + loop = VectorLoop(label, loop.operations[0:-1], loop.operations[-1]) loop.jump.setdescr(token) for op in loop.operations: if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -67,8 +67,8 @@ loop.graph = FakeDependencyGraph(loop) return loop - def pack(self, loop, l, r, input_type, output_type): - return Pack(loop.graph.nodes[1+l:1+r]) + def pack(self, loop, l, r, input_type=None, output_type=None): + return Pack(loop.graph.nodes[l:r]) def schedule(self, loop, packs, vec_reg_size=16, prepend_invariant=False, overwrite_funcs=None): @@ -115,6 +115,21 @@ assert node.count == 1 # must return here, then the test passed + def test_split_pack(self): + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) + f12 = raw_load_f(p0, i2, descr=double) + """) + ps = PackSet(16) + ps.packs = [self.pack(loop1, 0, 3)] + op1 = ps.packs[0].operations[0] + op2 = ps.packs[0].operations[1] + ps.split_overloaded_packs() + assert len(ps.packs) == 1 + assert ps.packs[0].leftmost() is op1.getoperation() + assert ps.packs[0].rightmost() is op2.getoperation() + def test_schedule_split_load(self): loop1 = self.parse_trace(""" f10 = raw_load_f(p0, i0, descr=float) @@ -124,10 +139,10 @@ f14 = raw_load_f(p0, i4, descr=float) f15 = raw_load_f(p0, i5, descr=float) """) - pack1 = self.pack(loop1, 0, 6, None, F32) + pack1 = self.pack(loop1, 0, 6) loop2 = self.schedule(loop1, [pack1]) loop3 = self.parse_trace(""" - v10[4xi32] = vec_raw_load_i(p0, i0, descr=float) + v10[4xi32] = vec_raw_load_f(p0, i0, descr=float) f10 = raw_load_f(p0, i4, descr=float) f11 = raw_load_f(p0, i5, descr=float) """, False) @@ -135,21 +150,21 @@ def test_int_to_float(self): loop1 = self.parse_trace(""" - i10 = raw_load(p0, i0, descr=long) - i11 = raw_load(p0, i1, descr=long) + i10 = raw_load_i(p0, i0, descr=long) + i11 = raw_load_i(p0, i1, descr=long) i12 = int_signext(i10, 4) i13 = int_signext(i11, 4) f10 = cast_int_to_float(i12) f11 = cast_int_to_float(i13) """) - pack1 = self.pack(loop1, 0, 2, None, I64) - pack2 = self.pack(loop1, 2, 4, I64, I32_2) - pack3 = self.pack(loop1, 4, 6, I32_2, F32_2) + pack1 = self.pack(loop1, 0, 2) + pack2 = self.pack(loop1, 2, 4) + pack3 = self.pack(loop1, 4, 6) loop2 = self.schedule(loop1, [pack1, pack2, pack3]) loop3 = self.parse_trace(""" - v10[i64|2] = vec_raw_load_i(p0, i0, descr=long) - v20[i32|2] = vec_int_signext(v10[i64|2], 4) - v30[f64|2] = vec_cast_int_to_float(v20[i32|2]) + v10[2xi64] = vec_raw_load_i(p0, i0, descr=long) + v20[2xi32] = vec_int_signext(v10[2xi64], 4) + v30[2xf64] = vec_cast_int_to_float(v20[2xi32]) """, False) self.assert_equal(loop2, loop3) @@ -161,12 +176,12 @@ pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[i64|2] = vec_box(2) - v20[i64|2] = vec_int_pack(v10[i64|2], i0, 0, 1) - v30[i64|2] = vec_int_pack(v20[i64|2], i1, 1, 1) - v40[i64|2] = vec_int_expand(73,2) + v10[2xi64] = vec_box_i() + v20[2xi64] = vec_int_pack(v10[2xi64], i0, 0, 1) + v30[2xi64] = vec_int_pack(v20[2xi64], i1, 1, 1) + v40[2xi64] = vec_int_expand(73,2) # - v50[i64|2] = vec_int_add(v30[i64|2], v40[i64|2]) + v50[2xi64] = vec_int_add(v30[2xi64], v40[2xi64]) """, False) self.assert_equal(loop2, loop3) @@ -177,12 +192,12 @@ pack1 = self.pack(loop1, 0, 2, F64, F64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[f64|2] = vec_box(2) - v20[f64|2] = vec_float_pack(v10[f64|2], f0, 0, 1) - v30[f64|2] = vec_float_pack(v20[f64|2], f1, 1, 1) - v40[f64|2] = vec_float_expand(73.0,2) + v10[2xf64] = vec_box_f() + v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1) + v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1) + v40[2xf64] = vec_float_expand(73.0,2) # - v50[f64|2] = vec_float_add(v30[f64|2], v40[f64|2]) + v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64]) """, False) self.assert_equal(loop2, loop3) @@ -197,13 +212,13 @@ pack2 = self.pack(loop1, 2, 4, F64, F64) loop2 = self.schedule(loop1, [pack1, pack2], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[f64|2] = vec_box(2) - v20[f64|2] = vec_float_pack(v10[f64|2], f0, 0, 1) - v30[f64|2] = vec_float_pack(v20[f64|2], f1, 1, 1) - v40[f64|2] = vec_float_expand(f5,2) # only expaned once + v10[2xf64] = vec_box_f() + v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1) + v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1) + v40[2xf64] = vec_float_expand(f5,2) # only expaned once # - v50[f64|2] = vec_float_add(v30[f64|2], v40[f64|2]) - v60[f64|2] = vec_float_add(v50[f64|2], v40[f64|2]) + v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64]) + v60[2xf64] = vec_float_add(v50[2xf64], v40[2xf64]) """, False) self.assert_equal(loop2, loop3) @@ -217,7 +232,7 @@ loop1 = self.parse_trace(""" i10 = int_signext(i1, 4) i11 = int_signext(i1, 4) - """, additional_args=['v10[i64|2]']) + """, additional_args=['v10[2xi64]']) pack1 = self.pack(loop1, 0, 2, I64, I32_2) var = self.find_input_arg('v10', loop1) def i1inv103204(v): @@ -227,20 +242,20 @@ 'getvector_of_box': i1inv103204, }) loop3 = self.parse_trace(""" - v11[i32|2] = vec_int_signext(v10[i64|2], 4) - """, False, additional_args=['v10[i64|2]']) + v11[2xi32] = vec_int_signext(v10[2xi64], 4) + """, False, additional_args=['v10[2xi64]']) self.assert_equal(loop2, loop3) def test_cast_float_to_int(self): loop1 = self.parse_trace(""" - f10 = raw_load(p0, i1, descr=double) - f11 = raw_load(p0, i2, descr=double) - f12 = raw_load(p0, i3, descr=double) - f13 = raw_load(p0, i4, descr=double) - f14 = raw_load(p0, i5, descr=double) - f15 = raw_load(p0, i6, descr=double) - f16 = raw_load(p0, i7, descr=double) - f17 = raw_load(p0, i8, descr=double) + f10 = raw_load_f(p0, i1, descr=double) + f11 = raw_load_f(p0, i2, descr=double) + f12 = raw_load_f(p0, i3, descr=double) + f13 = raw_load_f(p0, i4, descr=double) + f14 = raw_load_f(p0, i5, descr=double) + f15 = raw_load_f(p0, i6, descr=double) + f16 = raw_load_f(p0, i7, descr=double) + f17 = raw_load_f(p0, i8, descr=double) # i10 = cast_float_to_int(f10) i11 = cast_float_to_int(f11) @@ -281,31 +296,31 @@ '_prevent_signext': void }) loop3 = self.parse_trace(""" - v10[f64|2] = vec_raw_load_f(p0, i1, descr=double) - v11[f64|2] = vec_raw_load_f(p0, i3, descr=double) - v12[f64|2] = vec_raw_load_f(p0, i5, descr=double) - v13[f64|2] = vec_raw_load_f(p0, i7, descr=double) - v14[i32|2] = vec_cast_float_to_int(v10[f64|2]) - v15[i32|2] = vec_cast_float_to_int(v11[f64|2]) - v16[i32|2] = vec_cast_float_to_int(v12[f64|2]) - v17[i32|2] = vec_cast_float_to_int(v13[f64|2]) - v18[i16|2] = vec_int_signext(v14[i32|2],2) - v19[i16|2] = vec_int_signext(v15[i32|2],2) - v20[i16|2] = vec_int_signext(v16[i32|2],2) - v21[i16|2] = vec_int_signext(v17[i32|2],2) - v22[i16|4] = vec_int_pack(v18[i16|2], v19[i16|2], 2, 2) - v23[i16|6] = vec_int_pack(v22[i16|4], v20[i16|2], 4, 2) - v24[i16|8] = vec_int_pack(v23[i16|6], v21[i16|2], 6, 2) - vec_raw_store(p1, i1, v24[i16|8], descr=short) + v10[2xf64] = vec_raw_load_f(p0, i1, descr=double) + v11[2xf64] = vec_raw_load_f(p0, i3, descr=double) + v12[2xf64] = vec_raw_load_f(p0, i5, descr=double) + v13[2xf64] = vec_raw_load_f(p0, i7, descr=double) + v14[2xi32] = vec_cast_float_to_int(v10[2xf64]) + v15[2xi32] = vec_cast_float_to_int(v11[2xf64]) + v16[2xi32] = vec_cast_float_to_int(v12[2xf64]) + v17[2xi32] = vec_cast_float_to_int(v13[2xf64]) + v18[2xi16] = vec_int_signext(v14[2xi32],2) + v19[2xi16] = vec_int_signext(v15[2xi32],2) + v20[2xi16] = vec_int_signext(v16[2xi32],2) + v21[2xi16] = vec_int_signext(v17[2xi32],2) + v22[4xi16] = vec_int_pack(v18[2xi16], v19[2xi16], 2, 2) + v23[6xi16] = vec_int_pack(v22[4xi16], v20[2xi16], 4, 2) + v24[8xi16] = vec_int_pack(v23[6xi16], v21[2xi16], 6, 2) + vec_raw_store(p1, i1, v24[8xi16], descr=short) """, False) self.assert_equal(loop2, loop3) def test_cast_float_to_single_float(self): loop1 = self.parse_trace(""" - f10 = raw_load(p0, i1, descr=double) - f11 = raw_load(p0, i2, descr=double) - f12 = raw_load(p0, i3, descr=double) - f13 = raw_load(p0, i4, descr=double) + f10 = raw_load_f(p0, i1, descr=double) + f11 = raw_load_f(p0, i2, descr=double) + f12 = raw_load_f(p0, i3, descr=double) + f13 = raw_load_f(p0, i4, descr=double) # i10 = cast_float_to_singlefloat(f10) i11 = cast_float_to_singlefloat(f11) @@ -322,19 +337,19 @@ pack3 = self.pack(loop1, 8, 12, I32, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3]) loop3 = self.parse_trace(""" - v44[f64|2] = vec_raw_load_f(p0, i1, descr=double) - v45[f64|2] = vec_raw_load_f(p0, i3, descr=double) - v46[i32|2] = vec_cast_float_to_singlefloat(v44[f64|2]) - v47[i32|2] = vec_cast_float_to_singlefloat(v45[f64|2]) - v41[i32|4] = vec_int_pack(v46[i32|2], v47[i32|2], 2, 2) - vec_raw_store(p1, i1, v41[i32|4], descr=float) + v44[2xf64] = vec_raw_load_f(p0, i1, descr=double) + v45[2xf64] = vec_raw_load_f(p0, i3, descr=double) + v46[2xi32] = vec_cast_float_to_singlefloat(v44[2xf64]) + v47[2xi32] = vec_cast_float_to_singlefloat(v45[2xf64]) + v41[4xi32] = vec_int_pack(v46[2xi32], v47[2xi32], 2, 2) + vec_raw_store(p1, i1, v41[4xi32], descr=float) """, False) self.assert_equal(loop2, loop3) def test_all(self): loop1 = self.parse_trace(""" - i10 = raw_load(p0, i1, descr=long) - i11 = raw_load(p0, i2, descr=long) + i10 = raw_load_i(p0, i1, descr=long) + i11 = raw_load_i(p0, i2, descr=long) # i12 = int_and(i10, 255) i13 = int_and(i11, 255) @@ -347,20 +362,20 @@ pack3 = self.pack(loop1, 4, 6, I64, None) loop2 = self.schedule(loop1, [pack1,pack2,pack3], prepend_invariant=True) loop3 = self.parse_trace(""" - v9[i64|2] = vec_int_expand(255,2) - v10[i64|2] = vec_raw_load_i(p0, i1, descr=long) - v11[i64|2] = vec_int_and(v10[i64|2], v9[i64|2]) - guard_true(v11[i64|2]) [] + v9[2xi64] = vec_int_expand(255,2) + v10[2xi64] = vec_raw_load_i(p0, i1, descr=long) + v11[2xi64] = vec_int_and(v10[2xi64], v9[2xi64]) + guard_true(v11[2xi64]) [] """, False) self.assert_equal(loop2, loop3) def test_split_load_store(self): loop1 = self.parse_trace(""" - i10 = raw_load(p0, i1, descr=float) - i11 = raw_load(p0, i2, descr=float) - i12 = raw_load(p0, i3, descr=float) - i13 = raw_load(p0, i4, descr=float) + i10 = raw_load_f(p0, i1, descr=float) + i11 = raw_load_f(p0, i2, descr=float) + i12 = raw_load_f(p0, i3, descr=float) + i13 = raw_load_f(p0, i4, descr=float) raw_store(p0, i3, i10, descr=float) raw_store(p0, i4, i11, descr=float) """) @@ -368,10 +383,10 @@ pack2 = self.pack(loop1, 4, 6, I32_2, None) loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i32|4] = vec_raw_load_i(p0, i1, descr=float) - i10 = vec_int_unpack(v1[i32|4], 0, 1) + v1[4xi32] = vec_raw_load_i(p0, i1, descr=float) + i10 = vec_int_unpack(v1[4xi32], 0, 1) raw_store(p0, i3, i10, descr=float) - i11 = vec_int_unpack(v1[i32|4], 1, 1) + i11 = vec_int_unpack(v1[4xi32], 1, 1) raw_store(p0, i4, i11, descr=float) """, False) # unfortunate ui32 is the type for float32... the unsigned u is for @@ -386,9 +401,9 @@ pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i64|2] = vec_int_expand(255,2) - v2[i64|2] = vec_int_expand(i1,2) - v3[i64|2] = vec_int_and(v1[i64|2], v2[i64|2]) + v1[2xi64] = vec_int_expand(255,2) + v2[2xi64] = vec_int_expand(i1,2) + v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64]) """, False) self.assert_equal(loop2, loop3) @@ -400,9 +415,9 @@ pack1 = self.pack(loop1, 0, 2, I64, I64) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i64|2] = vec_int_expand(255, 2) - v2[i64|2] = vec_int_expand(i1, 2) - v3[i64|2] = vec_int_and(v1[i64|2], v2[i64|2]) + v1[2xi64] = vec_int_expand(255, 2) + v2[2xi64] = vec_int_expand(i1, 2) + v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64]) """, False) self.assert_equal(loop2, loop3) @@ -419,19 +434,19 @@ pack4 = self.pack(loop1, 4, 6, I64, I64) loop2 = self.schedule(loop1, [pack1,pack4], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[i64|2] = vec_int_expand(255,2) - v2[i64|2] = vec_box(2) - v3[i64|2] = vec_int_pack(v2[i64|2], i1, 0, 1) - v4[i64|2] = vec_int_pack(v3[i64|2], i2, 1, 1) - v5[i64|2] = vec_int_and(v1[i64|2], v4[i64|2]) - i10 = vec_int_unpack(v5[i64|2], 0, 1) + v1[2xi64] = vec_int_expand(255,2) + v2[2xi64] = vec_box_i() + v3[2xi64] = vec_int_pack(v2[2xi64], i1, 0, 1) + v4[2xi64] = vec_int_pack(v3[2xi64], i2, 1, 1) + v5[2xi64] = vec_int_and(v1[2xi64], v4[2xi64]) + i10 = vec_int_unpack(v5[2xi64], 0, 1) i12 = uint_floordiv(i10,1) - i11 = vec_int_unpack(v5[i64|2], 1, 1) + i11 = vec_int_unpack(v5[2xi64], 1, 1) i13 = uint_floordiv(i11,1) - v6[i64|2] = vec_box(2) - v7[i64|2] = vec_int_pack(v6[i64|2], i12, 0, 1) - v8[i64|2] = vec_int_pack(v7[i64|2], i13, 1, 1) - v9[i64|2] = vec_int_and(v4[i64|2], v8[i64|2]) + v6[2xi64] = vec_box_i() + v7[2xi64] = vec_int_pack(v6[2xi64], i12, 0, 1) + v8[2xi64] = vec_int_pack(v7[2xi64], i13, 1, 1) + v9[2xi64] = vec_int_and(v4[2xi64], v8[i64]) """, False) self.assert_equal(loop2, loop3) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -614,13 +614,9 @@ self.savings += benefit_factor * times - cost def cb_signext(self, pack): - op0 = pack.operations[0].getoperation() - size = op0.getarg(1).getint() - if pack.output_type is None: - return 1,0 - orig_size = pack.output_type.getsize() - if size == orig_size: - return 0,0 + left = pack.leftmost() + if left.cast_to_bytesize() == left.cast_from_bytesize(): + return 0, 0 # no benefit for this operation! needs many x86 instrs return 1,0 @@ -836,6 +832,8 @@ pack.split(newpacks, self.vec_reg_size) continue if load < Pack.FULL: + for op in pack.operations: + op.priority = -100 pack.clear() self.packs[i] = None continue diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -99,7 +99,7 @@ _attrs_ = ('datatype', 'bytesize', 'signed') datatype = '\x00' - bytesize = -1 + bytesize = -1 # -1 means the biggest size known to the machine signed = True def inittype(self): @@ -112,10 +112,17 @@ descr = self.getdescr() type = self.type if descr.is_array_of_floats() or descr.concrete_type == 'f': - type = FLOAT + type = 'f' self.bytesize = descr.get_item_size_in_bytes() self.sign = descr.is_item_signed() self.datatype = type + elif self.opnum == rop.INT_SIGNEXT: + arg0 = self.getarg(0) + arg1 = self.getarg(1) + self.setdatatype('i', arg1.value, arg0.signed) + elif self.is_typecast(): + ft,tt = self.cast_types() + self.setdatatype(tt, self.cast_to_bytesize(), tt == 'i') else: # pass through the type of the first input argument if self.numargs() == 0: @@ -123,7 +130,7 @@ arg0 = self.getarg(0) self.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) assert self.datatype != '\x00' - assert self.bytesize > 0 + #assert self.bytesize > 0 def setdatatype(self, data_type, bytesize, signed): self.datatype = data_type @@ -134,7 +141,7 @@ sign = '-' if not self.signed: sign = '+' - return 'Type(%s%s, %d)' % (sign, self.type, self.size) + return 'Type(%s%s, %d)' % (sign, self.type, self.bytesize) class AbstractResOpOrInputArg(AbstractValue, Typed): _attrs_ = ('_forwarded',) @@ -159,6 +166,7 @@ boolinverse = -1 vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement casts = ('\x00', -1, '\x00', -1) + count = -1 def getopnum(self): return self.opnum @@ -409,15 +417,6 @@ def forget_value(self): pass - def casts_box(self): - return False - - def cast_to(self): - return ('\x00',-1) - - def cast_from(self): - return ('\x00',-1) - def is_label(self): return self.getopnum() == rop.LABEL @@ -430,6 +429,26 @@ def returns_vector(self): return self.type != 'v' and self.vector == -2 + def is_typecast(self): + return False + + def cast_types(self): + return self.casts[0], self.casts[2] + + def cast_to_bytesize(self): + return self.casts[1] + + def cast_from_bytesize(self): + return self.casts[3] + + def casts_up(self): + return self.cast_to_bytesize() > self.cast_from_bytesize() + + def casts_down(self): + # includes the cast as noop + return self.cast_to_bytesize() <= self.cast_from_bytesize() + + # =================== # Top of the hierachy # =================== @@ -598,7 +617,7 @@ class CastOp(object): _mixin_ = True - def casts_box(self): + def is_typecast(self): return True def cast_to(self): @@ -614,15 +633,40 @@ return (to_type,size) def cast_from(self): - return ('\x00',-1) + type, size, a, b = self.casts + if size == -1: + return self.bytesize + return (type, size) + +class SignExtOp(object): + _mixin_ = True + + def is_typecast(self): + return True + + def cast_types(self): + return self.casts[0], self.casts[2] + + def cast_to_bytesize(self): + from rpython.jit.metainterp.history import ConstInt + arg = self.getarg(1) + assert isinstance(arg, ConstInt) + return arg.value + + def cast_from_bytesize(self): + arg = self.getarg(0) + return arg.bytesize class VectorOp(object): _mixin_ = True - _attrs_ = ('count',) def repr_rpython(self): return repr_rpython(self, 'bv') + def vector_bytesize(self): + assert self.count > 0 + return self.byte_size * self.count + def same_shape(self, other): """ NOT_RPYTHON """ if not other.is_vector(): @@ -675,10 +719,12 @@ class InputArgInt(IntOp, AbstractInputArg): def __init__(self, intval=0): self.setint(intval) + self.datatype = 'i' class InputArgFloat(FloatOp, AbstractInputArg): def __init__(self, f=longlong.ZEROF): self.setfloatstorage(f) + self.datatype = 'f' @staticmethod def fromfloat(x): @@ -687,13 +733,14 @@ class InputArgRef(RefOp, AbstractInputArg): def __init__(self, r=lltype.nullptr(llmemory.GCREF.TO)): self.setref_base(r) + self.datatype = 'r' def reset_value(self): self.setref_base(lltype.nullptr(llmemory.GCREF.TO)) class InputArgVector(VectorOp, AbstractInputArg): - def __init__(self): - pass + def __init__(self, datatype): + self.datatype = datatype def returns_vector(self): return True @@ -947,11 +994,10 @@ 'VEC_CAST_INT_TO_FLOAT/1/f', '_VEC_CAST_LAST', - 'VEC_INT_BOX/1/i', + 'VEC_BOX/0/if', 'VEC_INT_UNPACK/3/i', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) 'VEC_INT_PACK/4/i', # VEC_INT_PACK(vX, var/const, index, item_count) 'VEC_INT_EXPAND/2/i', # vX = VEC_INT_EXPAND(var/const, item_count) - 'VEC_FLOAT_BOX/1/f', 'VEC_FLOAT_UNPACK/3/f', # iX|fX = VEC_FLOAT_UNPACK(vX, index, item_count) 'VEC_FLOAT_PACK/4/f', # VEC_FLOAT_PACK(vX, var/const, index, item_count) 'VEC_FLOAT_EXPAND/2/f', # vX = VEC_FLOAT_EXPAND(var/const, item_count) @@ -1090,13 +1136,13 @@ ] _cast_ops = { - 'INT_SIGNEXT': ('i', 0, 'i', 0), 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4), 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8), 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4), 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8), - 'CAST_PTR_TO_INT': ('r', 0, 'i', 4), - 'CAST_INT_TO_PTR': ('i', 4, 'r', 0), + 'INT_SIGNEXT': ('i', 0, 'i', 0), + #'CAST_PTR_TO_INT': ('r', 0, 'i', 4), + #'CAST_INT_TO_PTR': ('i', 4, 'r', 0), } # ____________________________________________________________ @@ -1187,6 +1233,8 @@ else: baseclass = PlainResOp mixins = [arity2mixin.get(arity, N_aryOp)] + if name.startswith('VEC'): + mixins.append(VectorOp) if result_type == 'i': mixins.append(IntOp) elif result_type == 'f': @@ -1196,9 +1244,9 @@ else: assert result_type == 'n' if name in _cast_ops: + if name == "INT_SIGNEXT": + mixins.append(SignExtOp) mixins.append(CastOp) - if name.startswith('VEC'): - mixins.insert(1,VectorOp) cls_name = '%s_OP' % name bases = (get_base_class(tuple(mixins), baseclass),) diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -344,9 +344,19 @@ if res in self.vars: raise ParseError("Double assign to var %s in line: %s" % (res, line)) resop = self.create_op(opnum, args, res, descr, fail_args) + self.update_vector_count(resop, res) self.vars[res] = resop return resop + def update_vector_count(self, resop, var): + pattern = re.compile('.*\[(\d+)x(u?)(i|f)(\d+)\]') + match = pattern.match(var) + if match: + resop.count = int(match.group(1)) + resop.signed = not (match.group(2) == 'u') + resop.datatype = match.group(3) + resop.bytesize = int(match.group(4)) // 8 + def parse_op_no_result(self, line): opnum, args, descr, fail_args = self.parse_op(line) res = self.create_op(opnum, args, None, descr, fail_args) From noreply at buildbot.pypy.org Mon Sep 14 19:31:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 19:31:10 +0200 (CEST) Subject: [pypy-commit] pypy default: I *think* the inputargs should always contain InputArgXxx objects that Message-ID: <20150914173110.B2CDD1C1455@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79638:cfe5d8e88d3d Date: 2015-09-14 19:31 +0200 http://bitbucket.org/pypy/pypy/changeset/cfe5d8e88d3d/ Log: I *think* the inputargs should always contain InputArgXxx objects that are not forwarded. (Hitting the case from test_ll_random) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -134,6 +134,8 @@ self.final_jump_op = None def _prepare(self, inputargs, operations, allgcrefs): + for box in inputargs: + assert box.get_forwarded() is None cpu = self.assembler.cpu self.fm = X86FrameManager(cpu.get_baseofs_of_frame_field()) operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations, From noreply at buildbot.pypy.org Mon Sep 14 19:34:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 19:34:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Progress Message-ID: <20150914173448.B4F221C1DCE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79639:3aa319e4c7f0 Date: 2015-09-14 19:35 +0200 http://bitbucket.org/pypy/pypy/changeset/3aa319e4c7f0/ Log: Progress diff --git a/rpython/jit/backend/test/test_ll_random.py b/rpython/jit/backend/test/test_ll_random.py --- a/rpython/jit/backend/test/test_ll_random.py +++ b/rpython/jit/backend/test/test_ll_random.py @@ -2,9 +2,8 @@ from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr from rpython.rtyper import rclass from rpython.jit.backend.test import test_random -from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.history import ConstInt, ConstPtr -from rpython.jit.metainterp.history import BoxPtr +from rpython.jit.metainterp.resoperation import ResOperation, rop, optypes +from rpython.jit.metainterp.history import ConstInt, ConstPtr, getkind from rpython.jit.codewriter import heaptracker from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.rtyper.annlowlevel import llhelper @@ -101,10 +100,12 @@ kwds['hints'] = {'vtable': with_vtable._obj} for i in range(r.randrange(1, 5)): if r.random() < 0.1: + kind = 'r' TYPE = llmemory.GCREF else: + kind = 'i' TYPE = self.get_random_primitive_type(r) - fields.append(('f%d' % i, TYPE)) + fields.append(('%s%d' % (kind, i), TYPE)) S = type('S%d' % self.counter, *fields, **kwds) self.counter += 1 if cache: @@ -120,7 +121,7 @@ self.vtable_counter += 1 S = self.get_random_structure_type(r, with_vtable=vtable, cache=False) name = S._name - vtable.name = rclass.alloc_array_name(name) + heaptracker.set_testing_vtable_for_gcstruct(S, vtable, name) self.structure_types_and_vtables.append((S, vtable)) # return S, vtable @@ -168,7 +169,7 @@ if length == 0: raise test_random.CannotProduceOperation v_index = r.choice(self.intvars) - if not (0 <= v_index.value < length): + if not (0 <= v_index.getint() < length): v_index = ConstInt(r.random_integer() % length) return v_index @@ -242,14 +243,14 @@ if r.random() < 0.5: return GuardClassOperation.gen_guard(self, builder, r) else: - v = BoxPtr(lltype.nullptr(llmemory.GCREF.TO)) - op = ResOperation(rop.SAME_AS, [ConstPtr(v.value)], v) + NULL = lltype.nullptr(llmemory.GCREF.TO) + op = ResOperation(rop.SAME_AS_R, [ConstPtr(NULL)]) builder.loop.operations.append(op) v2, S2 = builder.get_structptr_var(r, must_have_vtable=True) vtable2 = S2._hints['vtable']._as_ptr() c_vtable2 = ConstAddr(llmemory.cast_ptr_to_adr(vtable2), builder.cpu) - op = ResOperation(self.opnum, [v, c_vtable2], None) + op = ResOperation(self.opnum, [op, c_vtable2], None) return op, False class ZeroPtrFieldOperation(test_random.AbstractOperation): @@ -263,7 +264,7 @@ choice = [] for name in names: FIELD = getattr(S, name) - if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc(): + if FIELD is lltype.Signed: # xxx should be a gc ptr, but works too choice.append(name) if not choice: raise test_random.CannotProduceOperation @@ -282,10 +283,12 @@ if names[0] == 'parent': names = names[1:] choice = [] + kind = optypes[self.opnum] for name in names: FIELD = getattr(S, name) if not isinstance(FIELD, lltype.Ptr): - choice.append(name) + if kind == 'n' or getkind(FIELD)[0] == kind: + choice.append(name) if not choice: raise test_random.CannotProduceOperation name = r.choice(choice) @@ -341,7 +344,8 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(TYPE, value)) == value: break builder.do(self.opnum, [v, w], descr) @@ -353,13 +357,14 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(TYPE, value)) == value: break builder.do(self.opnum, [v, v_index, w], descr) class NewOperation(test_random.AbstractOperation): - def size_descr(self, builder, S): - descr = builder.cpu.sizeof(S) + def size_descr(self, builder, S, *vtable): + descr = builder.cpu.sizeof(S, *vtable) descr._random_info = 'cpu.sizeof(...)' descr._random_type = S return descr @@ -367,13 +372,11 @@ def produce_into(self, builder, r): if self.opnum == rop.NEW_WITH_VTABLE: S, vtable = builder.get_random_structure_type_and_vtable(r) - args = [ConstAddr(llmemory.cast_ptr_to_adr(vtable), builder.cpu)] - descr = None + descr = self.size_descr(builder, S, vtable) else: S = builder.get_random_structure_type(r) - args = [] descr = self.size_descr(builder, S) - v_ptr = builder.do(self.opnum, args, descr) + v_ptr = builder.do(self.opnum, [], descr) builder.ptrvars.append((v_ptr, S)) class ArrayOperation(test_random.AbstractOperation): @@ -408,7 +411,8 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(A.OF, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(A.OF, value)) == value: break builder.do(self.opnum, [v, v_index, w], descr) @@ -486,7 +490,7 @@ class AbstractSetItemOperation(AbstractStringOperation): def produce_into(self, builder, r): v_string = self.get_string(builder, r) - if not isinstance(v_string, BoxPtr): + if isinstance(v_string, ConstPtr): raise test_random.CannotProduceOperation # setitem(Const, ...) v_index = builder.get_index(len(v_string.getref(self.ptr).chars), r) v_target = ConstInt(r.random_integer() % self.max) @@ -501,13 +505,15 @@ def produce_into(self, builder, r): v_srcstring = self.get_string(builder, r) v_dststring = self.get_string(builder, r) - if v_srcstring.value == v_dststring.value: # because it's not a + src = v_srcstring.getref(self.ptr) + dst = v_dststring.getref(self.ptr) + if src == dst: # because it's not a raise test_random.CannotProduceOperation # memmove(), but memcpy() - srclen = len(v_srcstring.getref(self.ptr).chars) - dstlen = len(v_dststring.getref(self.ptr).chars) + srclen = len(src.chars) + dstlen = len(dst.chars) v_length = builder.get_index(min(srclen, dstlen), r) - v_srcstart = builder.get_index(srclen - v_length.value + 1, r) - v_dststart = builder.get_index(dstlen - v_length.value + 1, r) + v_srcstart = builder.get_index(srclen - v_length.getint() + 1, r) + v_dststart = builder.get_index(dstlen - v_length.getint() + 1, r) builder.do(self.opnum, [v_srcstring, v_dststring, v_srcstart, v_dststart, v_length]) @@ -548,16 +554,22 @@ class BaseCallOperation(test_random.AbstractOperation): def non_raising_func_code(self, builder, r): subset = builder.subset_of_intvars(r) - if len(subset) == 0: - sum = "" - funcargs = "" + funcargs = ", ".join(['arg_%d' % i for i in range(len(subset))]) + sum = "intmask(%s)" % " + ".join( + ['arg_%d' % i for i in range(len(subset))] + ['42']) + if self.opnum == rop.CALL_I: + result = 'sum' + elif self.opnum == rop.CALL_F: + result = 'float(sum)' + elif self.opnum == rop.CALL_N: + result = '' else: - funcargs = ", ".join(['arg_%d' % i for i in range(len(subset))]) - sum = "intmask(%s)" % " + ".join(['arg_%d' % i for i in range(len(subset))]) + raise AssertionError(self.opnum) code = py.code.Source(""" def f(%s): - return %s - """ % (funcargs, sum)).compile() + sum = %s + return %s + """ % (funcargs, sum, result)).compile() d = {'intmask' : intmask} exec code in d return subset, d['f'] @@ -573,14 +585,25 @@ """ % funcargs).compile() vtableptr = v._hints['vtable']._as_ptr() d = { - 'ptr': S.value, + 'ptr': S.getref_base(), 'vtable' : vtableptr, 'LLException' : LLException, } exec code in d return subset, d['f'], vtableptr + def getresulttype(self): + if self.opnum == rop.CALL_I: + return lltype.Signed + elif self.opnum == rop.CALL_F: + return lltype.Float + elif self.opnum == rop.CALL_N or self.opnum == rop.COND_CALL: + return lltype.Void + else: + raise AssertionError(self.opnum) + def getcalldescr(self, builder, TP): + assert TP.RESULT == self.getresulttype() ef = EffectInfo.MOST_GENERAL return builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT, ef) @@ -589,17 +612,14 @@ def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f = self.non_raising_func_code(builder, r) - if len(subset) == 0: - RES = lltype.Void - else: - RES = lltype.Signed + RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -609,10 +629,7 @@ class CallOperationException(BaseCallOperation): def produce_into(self, builder, r): subset, f = self.non_raising_func_code(builder, r) - if len(subset) == 0: - RES = lltype.Void - else: - RES = lltype.Signed + RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) @@ -621,7 +638,7 @@ self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], descr=builder.getfaildescr()) op.setfailargs(builder.subset_of_intvars(r)) op._exc_box = None @@ -642,7 +659,7 @@ descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -658,7 +675,7 @@ args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr(), + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) @@ -682,7 +699,7 @@ if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [other_box], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) @@ -713,7 +730,7 @@ args = [v_cond, c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -723,17 +740,18 @@ OPERATIONS = test_random.OPERATIONS[:] for i in range(4): # make more common - OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC)) - OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC)) - OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC)) + OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC_I)) + OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC_I)) + OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC_I)) + OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC_I)) OPERATIONS.append(SetFieldOperation(rop.SETFIELD_GC)) OPERATIONS.append(ZeroPtrFieldOperation(rop.ZERO_PTR_FIELD)) OPERATIONS.append(SetInteriorFieldOperation(rop.SETINTERIORFIELD_GC)) OPERATIONS.append(NewOperation(rop.NEW)) OPERATIONS.append(NewOperation(rop.NEW_WITH_VTABLE)) - OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC)) - OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC)) + OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC_I)) + OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC_I)) OPERATIONS.append(SetArrayItemOperation(rop.SETARRAYITEM_GC)) OPERATIONS.append(NewArrayOperation(rop.NEW_ARRAY_CLEAR)) OPERATIONS.append(ArrayLenOperation(rop.ARRAYLEN_GC)) @@ -750,14 +768,16 @@ for i in range(2): OPERATIONS.append(GuardClassOperation(rop.GUARD_CLASS)) - OPERATIONS.append(CallOperation(rop.CALL)) - OPERATIONS.append(RaisingCallOperation(rop.CALL)) - OPERATIONS.append(RaisingCallOperationGuardNoException(rop.CALL)) - OPERATIONS.append(RaisingCallOperationWrongGuardException(rop.CALL)) - OPERATIONS.append(CallOperationException(rop.CALL)) OPERATIONS.append(CondCallOperation(rop.COND_CALL)) + OPERATIONS.append(RaisingCallOperation(rop.CALL_N)) + OPERATIONS.append(RaisingCallOperationGuardNoException(rop.CALL_N)) + OPERATIONS.append(RaisingCallOperationWrongGuardException(rop.CALL_N)) OPERATIONS.append(GuardNonNullClassOperation(rop.GUARD_NONNULL_CLASS)) +for _opnum in [rop.CALL_I, rop.CALL_F, rop.CALL_N]: + OPERATIONS.append(CallOperation(_opnum)) + OPERATIONS.append(CallOperationException(_opnum)) + LLtypeOperationBuilder.OPERATIONS = OPERATIONS # ____________________________________________________________ diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -8,7 +8,7 @@ from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef from rpython.jit.metainterp.resoperation import InputArgFloat -from rpython.jit.metainterp.executor import execute_nonspec_const +from rpython.jit.metainterp.executor import _execute_arglist, wrap_constant from rpython.jit.metainterp.resoperation import opname from rpython.jit.codewriter import longlong from rpython.rtyper.lltypesystem import lltype, rstr @@ -56,11 +56,11 @@ self.fakemetainterp._got_exc = None op = ResOperation(opnum, argboxes, descr) if opnum != rop.ZERO_PTR_FIELD: - assert op.type != VOID, op - c_result = execute_nonspec_const(self.cpu, self.fakemetainterp, - opnum, argboxes, descr, - type=op.type) - op.copy_value_from(c_result) + result = _execute_arglist(self.cpu, self.fakemetainterp, + opnum, argboxes, descr) + if result is not None: + c_result = wrap_constant(result) + op.copy_value_from(c_result) self.loop.operations.append(op) return op @@ -300,6 +300,8 @@ elif v_result.type == FLOAT: builder.floatvars.append(v_result) assert self.boolres != True + elif v_result.type == VOID: + assert self.boolres != True else: raise NotImplementedError(v_result) @@ -828,6 +830,8 @@ op = self.should_fail_by if not op.getfailargs(): return False + for _fail_box in fail_args: + _fail_box.set_forwarded(None) # generate the branch: a sequence of operations that ends in a FINISH subloop = DummyLoop([]) self.subloops.append(subloop) # keep around for debugging From noreply at buildbot.pypy.org Mon Sep 14 19:49:15 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 14 Sep 2015 19:49:15 +0200 (CEST) Subject: [pypy-commit] pypy default: Hack for zero_ptr_field Message-ID: <20150914174915.E07861C1EA1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79640:b4ab9fb41dcd Date: 2015-09-14 19:49 +0200 http://bitbucket.org/pypy/pypy/changeset/b4ab9fb41dcd/ Log: Hack for zero_ptr_field diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -61,6 +61,13 @@ if result is not None: c_result = wrap_constant(result) op.copy_value_from(c_result) + else: + import ctypes + addr = self.cpu.cast_gcref_to_int(argboxes[0].getref_base()) + offset = argboxes[1].getint() + assert (offset % ctypes.sizeof(ctypes.c_long)) == 0 + ptr = ctypes.cast(addr, ctypes.POINTER(ctypes.c_long)) + ptr[offset / ctypes.sizeof(ctypes.c_long)] = 0 self.loop.operations.append(op) return op From noreply at buildbot.pypy.org Mon Sep 14 20:31:03 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 14 Sep 2015 20:31:03 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: work in progress moving vecop creation to OpHelpers Message-ID: <20150914183103.EA6841C1F6C@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79641:d3aaa1983ac4 Date: 2015-09-14 20:31 +0200 http://bitbucket.org/pypy/pypy/changeset/d3aaa1983ac4/ Log: work in progress moving vecop creation to OpHelpers diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -165,17 +165,9 @@ # raise AssertionError("getunpackopnum type %s not supported" % (type,)) -def getexpandopnum(type): - if type == INT: - return rop.VEC_INT_EXPAND - elif type == FLOAT: - return rop.VEC_FLOAT_EXPAND - # - raise AssertionError("getexpandopnum type %s not supported" % (type,)) - -UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, - rop.UINT_LT, rop.UINT_LE, - rop.UINT_GT, rop.UINT_GE) +#UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, +# rop.UINT_LT, rop.UINT_LE, +# rop.UINT_GT, rop.UINT_GE) #class Type(object): # """ The type of one operation. Saves type, size and sign. """ @@ -446,7 +438,7 @@ if not vecop: # 2) constant/variable expand this box # TODO just as one function call - vecop = self.expand(arg, i) + vecop = expand(state, pack, args, arg, i) state.setvector_of_box(arg, 0, vecop) pos = 0 continue @@ -696,26 +688,24 @@ assert index.value + count.value <= result.getcount() assert result.getcount() > arg0.getcount() -def expand(self, arg, argidx): +def expand(state, pack, op, arg, argidx): """ Expand a value into a vector box. useful for arith metic of one vector with a scalar (either constant/varialbe) """ - elem_count = self.input_type.getcount() - vbox = self.input_type.new_vector_box(elem_count) + vecop = OpHelpers.create_vec(OpHelpers.vector_for_type(arg.type), None, + arg.type, op.bytesize, op.signed, op.count) box_type = arg.type - expanded_map = self.sched_data.expanded_map - # note that heterogenous nodes are not yet tracked - already_expanded = expanded_map.get(arg, None) - if already_expanded: - return already_expanded + #expanded_map = state.expanded_map + ## note that heterogenous nodes are not yet tracked + #already_expanded = expanded_map.get(arg, None) + #if already_expanded: + # return already_expanded - ops = self.sched_data.invariant_oplist - variables = self.sched_data.invariant_vector_vars - if isinstance(arg,Box) and arg not in self.sched_data.inputargs: + ops = state.invariant_oplist + variables = state.invariant_vector_vars + if not arg.is_constant() and arg not in state.inputargs: ops = self.vecops variables = None - if isinstance(arg, BoxVector): - box_type = arg.gettype() for i, node in enumerate(self.getoperations()): op = node.getoperation() @@ -723,12 +713,12 @@ break i += 1 else: - expand_opnum = getexpandopnum(box_type) - op = ResOperation(expand_opnum, [arg, ConstInt(vbox.item_count)], vbox) + vecop = OpHelpers.create_expand(arg.type, arg, op.count) + ops.append(vecop) ops.append(op) if variables is not None: - variables.append(vbox) - expanded_map[arg] = vbox + variables.append(vecop) + expanded_map[arg] = vecop return vbox op = ResOperation(rop.VEC_BOX, [ConstInt(elem_count)], vbox) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -173,7 +173,7 @@ i10 = int_add(i0, 73) i11 = int_add(i1, 73) """) - pack1 = self.pack(loop1, 0, 2, I64, I64) + pack1 = self.pack(loop1, 0, 2) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" v10[2xi64] = vec_box_i() diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -825,6 +825,7 @@ state.renamer.start_renaming(accum.getoriginalbox(), result) def split_overloaded_packs(self): + import pdb; pdb. set_trace() newpacks = [] for i,pack in enumerate(self.packs): load = pack.pack_load(self.vec_reg_size) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -4,6 +4,8 @@ from rpython.rlib.objectmodel import compute_identity_hash from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.jit.codewriter import longlong +from rpython.jit.backend.llsupport.symbolic import (WORD as INT_WORD, + SIZEOF_FLOAT as FLOAT_WORD) class SettingForwardedOnAbstractValue(Exception): pass @@ -127,13 +129,24 @@ # pass through the type of the first input argument if self.numargs() == 0: return - arg0 = self.getarg(0) - self.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) + i = 0 + arg = self.getarg(i) + while arg.is_constant() and i+1 < self.numargs(): + i += 1 + arg = self.getarg(i) + if arg.is_constant(): + return + self.setdatatype(arg.datatype, arg.bytesize, arg.signed) assert self.datatype != '\x00' #assert self.bytesize > 0 def setdatatype(self, data_type, bytesize, signed): self.datatype = data_type + if bytesize == -1: + if data_type == 'i': + bytesize = INT_WORD + elif data_type == 'f': + bytesize = FLOAT_WORD self.bytesize = bytesize self.signed = signed @@ -994,13 +1007,10 @@ 'VEC_CAST_INT_TO_FLOAT/1/f', '_VEC_CAST_LAST', - 'VEC_BOX/0/if', - 'VEC_INT_UNPACK/3/i', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) - 'VEC_INT_PACK/4/i', # VEC_INT_PACK(vX, var/const, index, item_count) - 'VEC_INT_EXPAND/2/i', # vX = VEC_INT_EXPAND(var/const, item_count) - 'VEC_FLOAT_UNPACK/3/f', # iX|fX = VEC_FLOAT_UNPACK(vX, index, item_count) - 'VEC_FLOAT_PACK/4/f', # VEC_FLOAT_PACK(vX, var/const, index, item_count) - 'VEC_FLOAT_EXPAND/2/f', # vX = VEC_FLOAT_EXPAND(var/const, item_count) + 'VEC/0/if', + 'VEC_UNPACK/3/if', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) + 'VEC_PACK/4/if', # VEC_INT_PACK(vX, var/const, index, item_count) + 'VEC_EXPAND/2/if', # vX = VEC_INT_EXPAND(var/const, item_count) '_VEC_PURE_LAST', # 'INT_LT/2b/i', @@ -1554,3 +1564,22 @@ else: assert tp == 'f' return InputArgFloat() + + @staticmethod + def create_expand(datatype, arg, bytesize, signed, count): + if datatype == 'i': + opnum = rop.VEC_EXPAND_I + else: + assert datatype == 'f' + opnum = rop.VEC_EXPAND_F + return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count) + + @staticmethod + def create_vec(datatype, arg, bytesize, signed, count): + if type == 'i': + opnum = rop.VEC_I + else: + assert type == 'f' + opnum = rop.VEC_F + return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count) + From noreply at buildbot.pypy.org Tue Sep 15 09:16:05 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 15 Sep 2015 09:16:05 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: share up to 5 guards Message-ID: <20150915071605.0BE161C103C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79642:c06257c68c32 Date: 2015-09-15 09:16 +0200 http://bitbucket.org/pypy/pypy/changeset/c06257c68c32/ Log: share up to 5 guards 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 @@ -573,13 +573,15 @@ return else: guard_op = self.replace_op_with(op, op.getopnum()) - if self._last_guard_op: + if self._last_guard_op and self._last_guard_count < 5: op = self._copy_resume_data_from(guard_op, self._last_guard_op) + self._last_guard_count += 1 else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) self._last_guard_op = op + self._last_guard_count = 0 # for unrolling for farg in op.getfailargs(): if farg: From noreply at buildbot.pypy.org Tue Sep 15 12:13:50 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 15 Sep 2015 12:13:50 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: revived broken as_vector_operation, partly working now, still need to adapt it further to work in the current setup Message-ID: <20150915101350.8DCC81C03CF@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79643:d1e29e8b7db7 Date: 2015-09-15 12:13 +0200 http://bitbucket.org/pypy/pypy/changeset/d1e29e8b7db7/ Log: revived broken as_vector_operation, partly working now, still need to adapt it further to work in the current setup diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -1,7 +1,7 @@ from rpython.jit.metainterp.history import (VECTOR, FLOAT, INT, ConstInt, ConstFloat, TargetToken) from rpython.jit.metainterp.resoperation import (rop, ResOperation, - GuardResOp, VecOperation) + GuardResOp, VecOperation, OpHelpers) from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.renamer import Renamer @@ -437,10 +437,7 @@ pos, vecop = state.getvector_of_box(arg) if not vecop: # 2) constant/variable expand this box - # TODO just as one function call - vecop = expand(state, pack, args, arg, i) - state.setvector_of_box(arg, 0, vecop) - pos = 0 + expand(state, pack, args, arg, i) continue args[i] = vecop assemble_scattered_values(state, pack, args, i) @@ -688,18 +685,13 @@ assert index.value + count.value <= result.getcount() assert result.getcount() > arg0.getcount() -def expand(state, pack, op, arg, argidx): +def expand(state, pack, args, arg, index): """ Expand a value into a vector box. useful for arith metic of one vector with a scalar (either constant/varialbe) """ - vecop = OpHelpers.create_vec(OpHelpers.vector_for_type(arg.type), None, - arg.type, op.bytesize, op.signed, op.count) + left = pack.leftmost() box_type = arg.type - #expanded_map = state.expanded_map - ## note that heterogenous nodes are not yet tracked - #already_expanded = expanded_map.get(arg, None) - #if already_expanded: - # return already_expanded + expanded_map = state.expanded_map ops = state.invariant_oplist variables = state.invariant_vector_vars @@ -707,36 +699,40 @@ ops = self.vecops variables = None - for i, node in enumerate(self.getoperations()): + for i, node in enumerate(pack.operations): op = node.getoperation() - if not arg.same_box(op.getarg(argidx)): + if not arg.same_box(op.getarg(index)): break i += 1 else: - vecop = OpHelpers.create_expand(arg.type, arg, op.count) - ops.append(vecop) - ops.append(op) + # note that heterogenous nodes are not yet tracked + already_expanded = expanded_map.get(arg, None) + if already_expanded: + return already_expanded + vecop = OpHelpers.create_vec_expand(arg, op.bytesize, op.signed, pack.numops()) + state.oplist.append(vecop) if variables is not None: variables.append(vecop) expanded_map[arg] = vecop - return vbox + for i in range(vecop.count): + state.setvector_of_box(arg, i, vecop) + args[index] = vecop + return vecop - op = ResOperation(rop.VEC_BOX, [ConstInt(elem_count)], vbox) - ops.append(op) - opnum = getpackopnum(arg.type) - for i,node in enumerate(self.getoperations()): + vecop = OpHelpers.create_vec(arg.type, left.bytesize, left.signed) + state.oplist.append(vecop) + for i,node in enumerate(pack.operations): op = node.getoperation() - arg = op.getarg(argidx) - new_box = vbox.clonebox() - ci = ConstInt(i) - c1 = ConstInt(1) - op = ResOperation(opnum, [vbox,arg,ci,c1], new_box) - vbox = new_box - ops.append(op) + arg = op.getarg(index) + arguments = [vecop, arg, ConstInt(i), ConstInt(1)] + vecop = OpHelpers.create_vec_pack(arg.type, arguments, left.bytesize, + left.signed, vecop.count+1) + state.setvector_of_box(arg, i, vecop) + state.oplist.append(vecop) if variables is not None: - variables.append(vbox) - return vbox + variables.append(vecop) + args[index] = vecop class OpToVectorOp(object): def __init__(self): #, restrictargs, typeoutput): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -17,14 +17,6 @@ from rpython.jit.tool.oparser import parse as opparse from rpython.jit.tool.oparser_model import get_model -F64 = None #('f',8,False) -F32 = None #('f',4,False) -F32_2 = None #('f',4,False) -I64 = None #('i',8,True) -I32 = None #('i',4,True) -I32_2 = None #('i',4,True) -I16 = None #('i',2,True) - class FakePackSet(PackSet): def __init__(self, packs): self.packs = packs @@ -176,10 +168,10 @@ pack1 = self.pack(loop1, 0, 2) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[2xi64] = vec_box_i() - v20[2xi64] = vec_int_pack(v10[2xi64], i0, 0, 1) - v30[2xi64] = vec_int_pack(v20[2xi64], i1, 1, 1) - v40[2xi64] = vec_int_expand(73,2) + v10[0xi64] = vec_i() + v20[1xi64] = vec_pack_i(v10[2xi64], i0, 0, 1) + v30[2xi64] = vec_pack_i(v20[2xi64], i1, 1, 1) + v40[2xi64] = vec_expand_i(73) # v50[2xi64] = vec_int_add(v30[2xi64], v40[2xi64]) """, False) @@ -189,13 +181,13 @@ f10 = float_add(f0, 73.0) f11 = float_add(f1, 73.0) """) - pack1 = self.pack(loop1, 0, 2, F64, F64) + pack1 = self.pack(loop1, 0, 2) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[2xf64] = vec_box_f() - v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1) - v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1) - v40[2xf64] = vec_float_expand(73.0,2) + v10[0xf64] = vec_f() + v20[1xf64] = vec_pack_f(v10[2xf64], f0, 0, 1) + v30[2xf64] = vec_pack_f(v20[2xf64], f1, 1, 1) + v40[2xf64] = vec_expand_f(73.0) # v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64]) """, False) @@ -208,14 +200,14 @@ f12 = float_add(f10, f5) f13 = float_add(f11, f5) """) - pack1 = self.pack(loop1, 0, 2, F64, F64) - pack2 = self.pack(loop1, 2, 4, F64, F64) + pack1 = self.pack(loop1, 0, 2) + pack2 = self.pack(loop1, 2, 4) loop2 = self.schedule(loop1, [pack1, pack2], prepend_invariant=True) loop3 = self.parse_trace(""" - v10[2xf64] = vec_box_f() - v20[2xf64] = vec_float_pack(v10[2xf64], f0, 0, 1) - v30[2xf64] = vec_float_pack(v20[2xf64], f1, 1, 1) - v40[2xf64] = vec_float_expand(f5,2) # only expaned once + v10[0xf64] = vec_f() + v20[1xf64] = vec_pack_f(v10[2xf64], f0, 0, 1) + v30[2xf64] = vec_pack_f(v20[2xf64], f1, 1, 1) + v40[2xf64] = vec_expand_f(f5) # only expaned once # v50[2xf64] = vec_float_add(v30[2xf64], v40[2xf64]) v60[2xf64] = vec_float_add(v50[2xf64], v40[2xf64]) @@ -233,7 +225,7 @@ i10 = int_signext(i1, 4) i11 = int_signext(i1, 4) """, additional_args=['v10[2xi64]']) - pack1 = self.pack(loop1, 0, 2, I64, I32_2) + pack1 = self.pack(loop1, 0, 2) var = self.find_input_arg('v10', loop1) def i1inv103204(v): return 0, var @@ -284,11 +276,10 @@ raw_store(p1, i7, i24, descr=short) raw_store(p1, i8, i25, descr=short) """) - pack1 = self.pack(loop1, 0, 8, None, F64) - pack2 = self.pack(loop1, 8, 16, F64, I32_2) - I16_2 = None #Type('i',2,True) - pack3 = self.pack(loop1, 16, 24, I32_2, I16_2) - pack4 = self.pack(loop1, 24, 32, I16, None) + pack1 = self.pack(loop1, 0, 8) + pack2 = self.pack(loop1, 8, 16) + pack3 = self.pack(loop1, 16, 24) + pack4 = self.pack(loop1, 24, 32) def void(b,c): pass loop2 = self.schedule(loop1, [pack1,pack2,pack3,pack4], @@ -308,9 +299,9 @@ v19[2xi16] = vec_int_signext(v15[2xi32],2) v20[2xi16] = vec_int_signext(v16[2xi32],2) v21[2xi16] = vec_int_signext(v17[2xi32],2) - v22[4xi16] = vec_int_pack(v18[2xi16], v19[2xi16], 2, 2) - v23[6xi16] = vec_int_pack(v22[4xi16], v20[2xi16], 4, 2) - v24[8xi16] = vec_int_pack(v23[6xi16], v21[2xi16], 6, 2) + v22[4xi16] = vec_pack_i(v18[2xi16], v19[2xi16], 2, 2) + v23[6xi16] = vec_pack_i(v22[4xi16], v20[2xi16], 4, 2) + v24[8xi16] = vec_pack_i(v23[6xi16], v21[2xi16], 6, 2) vec_raw_store(p1, i1, v24[8xi16], descr=short) """, False) self.assert_equal(loop2, loop3) @@ -332,16 +323,16 @@ raw_store(p1, i3, i12, descr=float) raw_store(p1, i4, i13, descr=float) """) - pack1 = self.pack(loop1, 0, 4, None, F64) - pack2 = self.pack(loop1, 4, 8, F64, I32_2) - pack3 = self.pack(loop1, 8, 12, I32, None) + pack1 = self.pack(loop1, 0, 4) + pack2 = self.pack(loop1, 4, 8) + pack3 = self.pack(loop1, 8, 12) loop2 = self.schedule(loop1, [pack1,pack2,pack3]) loop3 = self.parse_trace(""" v44[2xf64] = vec_raw_load_f(p0, i1, descr=double) v45[2xf64] = vec_raw_load_f(p0, i3, descr=double) v46[2xi32] = vec_cast_float_to_singlefloat(v44[2xf64]) v47[2xi32] = vec_cast_float_to_singlefloat(v45[2xf64]) - v41[4xi32] = vec_int_pack(v46[2xi32], v47[2xi32], 2, 2) + v41[4xi32] = vec_pack_i(v46[2xi32], v47[2xi32], 2, 2) vec_raw_store(p1, i1, v41[4xi32], descr=float) """, False) self.assert_equal(loop2, loop3) @@ -357,12 +348,12 @@ guard_true(i12) [] guard_true(i13) [] """) - pack1 = self.pack(loop1, 0, 2, None, I64) - pack2 = self.pack(loop1, 2, 4, I64, I64) - pack3 = self.pack(loop1, 4, 6, I64, None) + pack1 = self.pack(loop1, 0, 2) + pack2 = self.pack(loop1, 2, 4) + pack3 = self.pack(loop1, 4, 6) loop2 = self.schedule(loop1, [pack1,pack2,pack3], prepend_invariant=True) loop3 = self.parse_trace(""" - v9[2xi64] = vec_int_expand(255,2) + v9[2xi64] = vec_expand_i(255) v10[2xi64] = vec_raw_load_i(p0, i1, descr=long) v11[2xi64] = vec_int_and(v10[2xi64], v9[2xi64]) guard_true(v11[2xi64]) [] @@ -379,14 +370,14 @@ raw_store(p0, i3, i10, descr=float) raw_store(p0, i4, i11, descr=float) """) - pack1 = self.pack(loop1, 0, 4, None, I32) - pack2 = self.pack(loop1, 4, 6, I32_2, None) + pack1 = self.pack(loop1, 0, 4) + pack2 = self.pack(loop1, 4, 6) loop2 = self.schedule(loop1, [pack1,pack2], prepend_invariant=True) loop3 = self.parse_trace(""" v1[4xi32] = vec_raw_load_i(p0, i1, descr=float) - i10 = vec_int_unpack(v1[4xi32], 0, 1) + i10 = vec_unpack_i(v1[4xi32], 0, 1) raw_store(p0, i3, i10, descr=float) - i11 = vec_int_unpack(v1[4xi32], 1, 1) + i11 = vec_unpack_i(v1[4xi32], 1, 1) raw_store(p0, i4, i11, descr=float) """, False) # unfortunate ui32 is the type for float32... the unsigned u is for @@ -398,11 +389,11 @@ i10 = int_and(255, i1) i11 = int_and(255, i1) """) - pack1 = self.pack(loop1, 0, 2, I64, I64) + pack1 = self.pack(loop1, 0, 2) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[2xi64] = vec_int_expand(255,2) - v2[2xi64] = vec_int_expand(i1,2) + v1[2xi64] = vec_expand_i(255) + v2[2xi64] = vec_expand_i(i1) v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64]) """, False) self.assert_equal(loop2, loop3) @@ -412,11 +403,11 @@ i10 = int_and(255, i1) i11 = int_and(255, i1) """) - pack1 = self.pack(loop1, 0, 2, I64, I64) + pack1 = self.pack(loop1, 0, 2) loop2 = self.schedule(loop1, [pack1], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[2xi64] = vec_int_expand(255, 2) - v2[2xi64] = vec_int_expand(i1, 2) + v1[2xi64] = vec_expand_i(255) + v2[2xi64] = vec_expand_i(i1) v3[2xi64] = vec_int_and(v1[2xi64], v2[2xi64]) """, False) self.assert_equal(loop2, loop3) @@ -430,22 +421,22 @@ i14 = int_and(i1, i12) i15 = int_and(i2, i13) """) - pack1 = self.pack(loop1, 0, 2, I64, I64) - pack4 = self.pack(loop1, 4, 6, I64, I64) + pack1 = self.pack(loop1, 0, 2) + pack4 = self.pack(loop1, 4, 6) loop2 = self.schedule(loop1, [pack1,pack4], prepend_invariant=True) loop3 = self.parse_trace(""" - v1[2xi64] = vec_int_expand(255,2) - v2[2xi64] = vec_box_i() - v3[2xi64] = vec_int_pack(v2[2xi64], i1, 0, 1) - v4[2xi64] = vec_int_pack(v3[2xi64], i2, 1, 1) + v1[2xi64] = vec_expand_i(255) + v2[0xi64] = vec_i() + v3[1xi64] = vec_pack_i(v2[2xi64], i1, 0, 1) + v4[2xi64] = vec_pack_i(v3[2xi64], i2, 1, 1) v5[2xi64] = vec_int_and(v1[2xi64], v4[2xi64]) - i10 = vec_int_unpack(v5[2xi64], 0, 1) + i10 = vec_unpack_i(v5[2xi64], 0, 1) i12 = uint_floordiv(i10,1) - i11 = vec_int_unpack(v5[2xi64], 1, 1) + i11 = vec_unpack_i(v5[2xi64], 1, 1) i13 = uint_floordiv(i11,1) - v6[2xi64] = vec_box_i() - v7[2xi64] = vec_int_pack(v6[2xi64], i12, 0, 1) - v8[2xi64] = vec_int_pack(v7[2xi64], i13, 1, 1) + v6[0xi64] = vec_i() + v7[1xi64] = vec_pack_i(v6[2xi64], i12, 0, 1) + v8[2xi64] = vec_pack_i(v7[2xi64], i13, 1, 1) v9[2xi64] = vec_int_and(v4[2xi64], v8[i64]) """, False) self.assert_equal(loop2, loop3) @@ -457,7 +448,7 @@ f12 = cast_int_to_float(i3) f13 = cast_int_to_float(i4) """) - pack = self.pack(trace, 0, 4, I64, F32) + pack = self.pack(trace, 0, 4) packs = [] pack.split(packs, 16) packs.append(pack) @@ -468,7 +459,7 @@ i10 = int_add(i1, i3) i11 = int_add(i2, i3) """) - pack = self.pack(trace, 0, 2, I16, I16) + pack = self.pack(trace, 0, 2) packset = FakePackSet([pack]) packset.split_overloaded_packs() assert len(packset.packs) == 0 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 @@ -163,6 +163,7 @@ assert remap.get(y, y) is None else: assert x.same_box(remap.get(y, y)) + assert x.same_shape(remap.get(y, y)) else: fail_args1 = set(op1.getfailargs()) fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()]) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -825,7 +825,6 @@ state.renamer.start_renaming(accum.getoriginalbox(), result) def split_overloaded_packs(self): - import pdb; pdb. set_trace() newpacks = [] for i,pack in enumerate(self.packs): load = pack.pack_load(self.vec_reg_size) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -36,6 +36,9 @@ def same_box(self, other): return self is other + def same_shape(self, other): + return self is other + def repr_short(self, memo): return self.repr(memo) @@ -71,6 +74,9 @@ def returns_vector(self): return False + def is_vector(self): + return False + def ResOperation(opnum, args, descr=None): cls = opclasses[opnum] op = cls() @@ -684,16 +690,11 @@ """ NOT_RPYTHON """ if not other.is_vector(): return False - # - # TODO ? if other.item_size == -1 or self.item_size == -1: - # fallback for tests that do not specify the size - # return True - # if self.datatype != other.datatype: return False if self.bytesize != other.bytesize: return False - if self.signed!= other.signed: + if self.signed != other.signed: return False if self.count != other.count: return False @@ -752,8 +753,8 @@ self.setref_base(lltype.nullptr(llmemory.GCREF.TO)) class InputArgVector(VectorOp, AbstractInputArg): - def __init__(self, datatype): - self.datatype = datatype + def __init__(self): + self.type = 'v' def returns_vector(self): return True @@ -1008,9 +1009,9 @@ '_VEC_CAST_LAST', 'VEC/0/if', - 'VEC_UNPACK/3/if', # iX|fX = VEC_INT_UNPACK(vX, index, item_count) - 'VEC_PACK/4/if', # VEC_INT_PACK(vX, var/const, index, item_count) - 'VEC_EXPAND/2/if', # vX = VEC_INT_EXPAND(var/const, item_count) + 'VEC_UNPACK/3/if', # iX|fX = VEC_INT_UNPACK(vX, index, count) + 'VEC_PACK/4/if', # VEC_INT_PACK(vX, var/const, index, count) + 'VEC_EXPAND/1/if', # vX = VEC_INT_EXPAND(var/const) '_VEC_PURE_LAST', # 'INT_LT/2b/i', @@ -1566,20 +1567,29 @@ return InputArgFloat() @staticmethod - def create_expand(datatype, arg, bytesize, signed, count): - if datatype == 'i': + def create_vec_expand(arg, bytesize, signed, count): + if arg.type == 'i': opnum = rop.VEC_EXPAND_I else: - assert datatype == 'f' + assert arg.type == 'f' opnum = rop.VEC_EXPAND_F - return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count) + return VecOperationNew(opnum, [arg], arg.type, bytesize, signed, count) @staticmethod - def create_vec(datatype, arg, bytesize, signed, count): - if type == 'i': + def create_vec(datatype, bytesize, signed): + if datatype == 'i': opnum = rop.VEC_I else: - assert type == 'f' + assert datatype == 'f' opnum = rop.VEC_F - return VecOperationNew(opnum, [arg], datatype, bytesize, signed, count) + return VecOperationNew(opnum, [], datatype, bytesize, signed, 0) + @staticmethod + def create_vec_pack(datatype, args, bytesize, signed, count): + if datatype == 'i': + opnum = rop.VEC_PACK_I + else: + assert datatype == 'f' + opnum = rop.VEC_PACK_F + return VecOperationNew(opnum, args, datatype, bytesize, signed, count) + diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -8,8 +8,8 @@ from rpython.jit.tool.oparser_model import get_model from rpython.jit.metainterp.resoperation import rop, ResOperation, \ - InputArgInt, InputArgRef, InputArgFloat, ResOpWithDescr, N_aryOp, \ - UnaryOp, PlainResOp, optypes + InputArgInt, InputArgRef, InputArgFloat, InputArgVector, \ + ResOpWithDescr, N_aryOp, UnaryOp, PlainResOp, optypes class ParseError(Exception): pass @@ -191,6 +191,9 @@ v = InputArgInt(0) elif elem.startswith('f'): v = InputArgFloat(0.0) + elif elem.startswith('v'): + v = InputArgVector() + elem = self.update_vector(v, elem) else: from rpython.rtyper.lltypesystem import lltype, llmemory assert elem.startswith('p') @@ -231,6 +234,11 @@ elif arg.startswith('ConstInt('): name = arg[len('ConstInt('):-1] return self.get_const(name, 'int') + elif arg.startswith('v') and '[' in arg: + i = 1 + while i < len(arg) and arg[i] != '[': + i += 1 + return self.getvar(arg[:i]) elif arg == 'None': return None elif arg == 'NULL': @@ -344,11 +352,11 @@ if res in self.vars: raise ParseError("Double assign to var %s in line: %s" % (res, line)) resop = self.create_op(opnum, args, res, descr, fail_args) - self.update_vector_count(resop, res) + res = self.update_vector(resop, res) self.vars[res] = resop return resop - def update_vector_count(self, resop, var): + def update_vector(self, resop, var): pattern = re.compile('.*\[(\d+)x(u?)(i|f)(\d+)\]') match = pattern.match(var) if match: @@ -356,6 +364,8 @@ resop.signed = not (match.group(2) == 'u') resop.datatype = match.group(3) resop.bytesize = int(match.group(4)) // 8 + return var[:var.find('[')] + return var def parse_op_no_result(self, line): opnum, args, descr, fail_args = self.parse_op(line) From noreply at buildbot.pypy.org Tue Sep 15 12:49:07 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 15 Sep 2015 12:49:07 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: input arg bytesize default to the hardware offered precision (word size) Message-ID: <20150915104908.020CA1C0589@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79644:b57463d82b50 Date: 2015-09-15 12:49 +0200 http://bitbucket.org/pypy/pypy/changeset/b57463d82b50/ Log: input arg bytesize default to the hardware offered precision (word size) diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -19,6 +19,7 @@ def post_schedule(self): loop = self.graph.loop self.renamer.rename(loop.jump) + loop.operations = self.oplist def profitable(self): return self.costmodel.profitable() @@ -93,7 +94,7 @@ node.clear_dependencies() node.emitted = True - def walk_and_emit(self, state): # TODO oplist, renamer, unpack=False): + def walk_and_emit(self, state): """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) @@ -515,9 +516,6 @@ #assert vecop is not None #args[i] = vecop -def before_argument_transform(self, args): - pass - def check_if_pack_supported(self, pack): op0 = pack.operations[0].getoperation() if self.input_type is None: @@ -534,90 +532,6 @@ # see assembler for comment why raise NotAProfitableLoop -#def transform_result(self, result): -# if result is None: -# return None -# vbox = self.new_result_vector_box() -# # -# # mark the position and the vbox in the hash -# for i, node in enumerate(self.getoperations()): -# if i >= vbox.getcount(): -# break -# op = node.getoperation() -# self.sched_data.setvector_of_box(op, i, vbox) -# return vbox - -#def new_result_vector_box(self): -# type = self.output_type.gettype() -# size = self.output_type.getsize() -# count = min(self.output_type.getcount(), len(self.pack.operations)) -# signed = self.output_type.signed -# return BoxVector(type, count, size, signed) - -#def getoperations(self): -# return self.pack.operations - -#def transform_arguments(self, args): -# """ Transforming one argument to a vector box argument -# The following cases can occur: -# 1) argument is present in the box_to_vbox map. -# a) vector can be reused immediatly (simple case) -# b) vector is to big -# c) vector is to small -# 2) argument is not known to reside in a vector -# a) expand vars/consts before the label and add as argument -# b) expand vars created in the loop body -# """ -# for i,arg in enumerate(args): -# if arg.returns_vector(): -# continue -# if not self.is_vector_arg(i): -# continue -# box_pos, vbox = self.sched_data.getvector_of_box(arg) -# if not vbox: -# # constant/variable expand this box -# vbox = self.expand(arg, i) -# self.sched_data.setvector_of_box(arg, 0, vbox) -# box_pos = 0 -# # convert size i64 -> i32, i32 -> i64, ... -# if self.input_type.getsize() > 0 and \ -# self.input_type.getsize() != vbox.getsize(): -# vbox = self.extend(vbox, self.input_type) - -# # use the input as an indicator for the pack type -# packable = self.input_type.getcount() -# packed = vbox.getcount() -# assert packed >= 0 -# assert packable >= 0 -# if packed > packable: -# # the argument has more items than the operation is able to process! -# # box_pos == 0 then it is already at the right place -# if box_pos != 0: -# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# self.update_arg_in_vector_pos(i, args[i]) -# #self.update_input_output(self.pack) -# continue -# else: -# assert vbox is not None -# args[i] = vbox -# continue -# vboxes = self.vector_boxes_for_args(i) -# if packed < packable and len(vboxes) > 1: -# # the argument is scattered along different vector boxes -# args[i] = self.gather(vboxes, packable) -# self.update_arg_in_vector_pos(i, args[i]) -# continue -# if box_pos != 0: -# # The vector box is at a position != 0 but it -# # is required to be at position 0. Unpack it! -# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# self.update_arg_in_vector_pos(i, args[i]) -# continue -# #self.update_input_output(self.pack) -# # -# assert vbox is not None -# args[i] = vbox - def extend(self, vbox, newtype): assert vbox.gettype() == newtype.gettype() if vbox.gettype() == INT: @@ -734,154 +648,6 @@ variables.append(vecop) args[index] = vecop -class OpToVectorOp(object): - def __init__(self): #, restrictargs, typeoutput): - pass - #self.args = list(restrictargs) # do not use a tuple. rpython cannot union - #self.out = typeoutput - -class OpToVectorOpConv(OpToVectorOp): - def __init__(self, intype, outtype): - #self.from_size = intype.getsize() - #self.to_size = outtype.getsize() - #OpToVectorOp.__init__(self, (intype, ), outtype) - pass - - def new_result_vector_box(self): - type = self.output_type.gettype() - size = self.to_size - count = self.output_type.getcount() - vec_reg_size = self.sched_data.vec_reg_size - if count * size > vec_reg_size: - count = vec_reg_size // size - signed = self.output_type.signed - assert type in ('i','f') - assert size > 0 - assert count > 1 - return BoxVector(type, count, size, signed) - - def get_output_type_given(self, input_type, op): - return self.result_ptype - - def get_input_type_given(self, output_type, op): - return self.arg_ptypes[0] - - def force_input(self, ptype): - return self.arg_ptypes[0] - -class SignExtToVectorOp(OpToVectorOp): - def __init__(self, intype, outtype): - OpToVectorOp.__init__(self, intype, outtype) - self.size = -1 - - def before_argument_transform(self, args): - sizearg = args[1] - assert isinstance(sizearg, ConstInt) - self.size = sizearg.value - - def new_result_vector_box(self): - type = self.output_type.gettype() - count = self.input_type.getcount() - vec_reg_size = self.sched_data.vec_reg_size - if count * self.size > vec_reg_size: - count = vec_reg_size // self.size - signed = self.input_type.signed - assert type in ('i','f') - assert self.size > 0 - assert count > 1 - return BoxVector(type, count, self.size, signed) - - def get_output_type_given(self, input_type, op): - sizearg = op.getarg(1) - assert isinstance(sizearg, ConstInt) - output_type = input_type.clone() - output_type.setsize(sizearg.value) - return output_type - - def get_input_type_given(self, output_type, op): - raise AssertionError("can never infer input type!") - -class LoadToVectorLoad(OpToVectorOp): - def __init__(self): - OpToVectorOp.__init__(self, (), TypeRestrict()) - - # OLD def before_argument_transform(self, args): - #count = min(self.output_type.getcount(), len(self.getoperations())) - #args.append(ConstInt(count)) - - def get_output_type_given(self, input_type, op): - return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) - - def get_input_type_given(self, output_type, op): - return None - -class StoreToVectorStore(OpToVectorOp): - """ Storing operations are special because they are not allowed - to store to memory if the vector is not fully filled. - Thus a modified split_pack function. - """ - def __init__(self): - OpToVectorOp.__init__(self, (None, None, TypeRestrict()), None) - self.has_descr = True - - def must_be_full_but_is_not(self, pack): - vrs = self.sched_data.vec_reg_size - it = pack.input_type - return it.getsize() * it.getcount() < vrs - - def get_output_type_given(self, input_type, op): - return None - - def get_input_type_given(self, output_type, op): - return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) - -class PassThroughOp(OpToVectorOp): - """ This pass through is only applicable if the target - operation is capable of handling vector operations. - Guard true/false is such an example. - """ - def __init__(self, args): - OpToVectorOp.__init__(self, args, None) - - def get_output_type_given(self, input_type, op): - return None - - def get_input_type_given(self, output_type, op): - raise AssertionError("cannot infer input type from output type") - - - -#def determine_input_output_types(pack, node, forward): -# """ This function is two fold. If moving forward, it -# gets an input type from the packs output type and returns -# the transformed packtype. -# -# Moving backward, the origins pack input type is the output -# type and the transformation of the packtype (in reverse direction) -# is the input -# """ -# op = node.getoperation() -# op2vecop = determine_trans(op) -# if forward: -# input_type = op2vecop.force_input(pack.output_type) -# output_type = op2vecop.get_output_type_given(input_type, op) -# if output_type: -# output_type = output_type.clone() -# else: -# # going backwards, things are not that easy anymore -# output_type = pack.input_type -# input_type = op2vecop.get_input_type_given(output_type, op) -# if input_type: -# input_type = input_type.clone() -# -# return input_type, output_type - -def determine_trans(op): - op2vecop = trans.MAPPING.get(op.vector, None) - if op2vecop is None: - raise NotImplementedError("missing vecop for '%s'" % (op.getopname(),)) - return op2vecop - class VecScheduleState(SchedulerState): def __init__(self, graph, packset, cpu, costmodel): SchedulerState.__init__(self, graph) @@ -903,8 +669,6 @@ self.unpack_from_vector(loop.jump) SchedulerState.post_schedule(self) - self.graph.loop.operations = self.oplist - # add accumulation info to the descriptor #for version in self.loop.versions: # # this needs to be done for renamed (accum arguments) @@ -945,7 +709,6 @@ assert node.pack.numops() > 1 for node in node.pack.operations: scheduler.mark_emitted(node, self) - # TODO op2vecop = determine_trans(node.pack.leftmost()) turn_to_vector(self, node.pack) return True return False @@ -1219,3 +982,239 @@ self.left = left self.right = right self.accum = accum + +#class OpToVectorOp(object): +# def __init__(self): #, restrictargs, typeoutput): +# pass +# #self.args = list(restrictargs) # do not use a tuple. rpython cannot union +# #self.out = typeoutput +# +#class OpToVectorOpConv(OpToVectorOp): +# def __init__(self, intype, outtype): +# #self.from_size = intype.getsize() +# #self.to_size = outtype.getsize() +# #OpToVectorOp.__init__(self, (intype, ), outtype) +# pass +# +# def new_result_vector_box(self): +# type = self.output_type.gettype() +# size = self.to_size +# count = self.output_type.getcount() +# vec_reg_size = self.sched_data.vec_reg_size +# if count * size > vec_reg_size: +# count = vec_reg_size // size +# signed = self.output_type.signed +# assert type in ('i','f') +# assert size > 0 +# assert count > 1 +# return BoxVector(type, count, size, signed) +# +# def get_output_type_given(self, input_type, op): +# return self.result_ptype +# +# def get_input_type_given(self, output_type, op): +# return self.arg_ptypes[0] +# +# def force_input(self, ptype): +# return self.arg_ptypes[0] +# +#class SignExtToVectorOp(OpToVectorOp): +# def __init__(self, intype, outtype): +# OpToVectorOp.__init__(self, intype, outtype) +# self.size = -1 +# +# def before_argument_transform(self, args): +# sizearg = args[1] +# assert isinstance(sizearg, ConstInt) +# self.size = sizearg.value +# +# def new_result_vector_box(self): +# type = self.output_type.gettype() +# count = self.input_type.getcount() +# vec_reg_size = self.sched_data.vec_reg_size +# if count * self.size > vec_reg_size: +# count = vec_reg_size // self.size +# signed = self.input_type.signed +# assert type in ('i','f') +# assert self.size > 0 +# assert count > 1 +# return BoxVector(type, count, self.size, signed) +# +# def get_output_type_given(self, input_type, op): +# sizearg = op.getarg(1) +# assert isinstance(sizearg, ConstInt) +# output_type = input_type.clone() +# output_type.setsize(sizearg.value) +# return output_type +# +# def get_input_type_given(self, output_type, op): +# raise AssertionError("can never infer input type!") +# +#class LoadToVectorLoad(OpToVectorOp): +# def __init__(self): +# OpToVectorOp.__init__(self, (), TypeRestrict()) +# +# # OLD def before_argument_transform(self, args): +# #count = min(self.output_type.getcount(), len(self.getoperations())) +# #args.append(ConstInt(count)) +# +# def get_output_type_given(self, input_type, op): +# return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) +# +# def get_input_type_given(self, output_type, op): +# return None +# +#class StoreToVectorStore(OpToVectorOp): +# """ Storing operations are special because they are not allowed +# to store to memory if the vector is not fully filled. +# Thus a modified split_pack function. +# """ +# def __init__(self): +# OpToVectorOp.__init__(self, (None, None, TypeRestrict()), None) +# self.has_descr = True +# +# def must_be_full_but_is_not(self, pack): +# vrs = self.sched_data.vec_reg_size +# it = pack.input_type +# return it.getsize() * it.getcount() < vrs +# +# def get_output_type_given(self, input_type, op): +# return None +# +# def get_input_type_given(self, output_type, op): +# return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) +# +#class PassThroughOp(OpToVectorOp): +# """ This pass through is only applicable if the target +# operation is capable of handling vector operations. +# Guard true/false is such an example. +# """ +# def __init__(self, args): +# OpToVectorOp.__init__(self, args, None) +# +# def get_output_type_given(self, input_type, op): +# return None +# +# def get_input_type_given(self, output_type, op): +# raise AssertionError("cannot infer input type from output type") +# +# +# +##def determine_input_output_types(pack, node, forward): +## """ This function is two fold. If moving forward, it +## gets an input type from the packs output type and returns +## the transformed packtype. +## +## Moving backward, the origins pack input type is the output +## type and the transformation of the packtype (in reverse direction) +## is the input +## """ +## op = node.getoperation() +## op2vecop = determine_trans(op) +## if forward: +## input_type = op2vecop.force_input(pack.output_type) +## output_type = op2vecop.get_output_type_given(input_type, op) +## if output_type: +## output_type = output_type.clone() +## else: +## # going backwards, things are not that easy anymore +## output_type = pack.input_type +## input_type = op2vecop.get_input_type_given(output_type, op) +## if input_type: +## input_type = input_type.clone() +## +## return input_type, output_type +# +#def determine_trans(op): +# op2vecop = trans.MAPPING.get(op.vector, None) +# if op2vecop is None: +# raise NotImplementedError("missing vecop for '%s'" % (op.getopname(),)) +# return op2vecop + + +#def before_argument_transform(self, args): +# pass + +#def transform_result(self, result): +# if result is None: +# return None +# vbox = self.new_result_vector_box() +# # +# # mark the position and the vbox in the hash +# for i, node in enumerate(self.getoperations()): +# if i >= vbox.getcount(): +# break +# op = node.getoperation() +# self.sched_data.setvector_of_box(op, i, vbox) +# return vbox + +#def new_result_vector_box(self): +# type = self.output_type.gettype() +# size = self.output_type.getsize() +# count = min(self.output_type.getcount(), len(self.pack.operations)) +# signed = self.output_type.signed +# return BoxVector(type, count, size, signed) + +#def getoperations(self): +# return self.pack.operations + +#def transform_arguments(self, args): +# """ Transforming one argument to a vector box argument +# The following cases can occur: +# 1) argument is present in the box_to_vbox map. +# a) vector can be reused immediatly (simple case) +# b) vector is to big +# c) vector is to small +# 2) argument is not known to reside in a vector +# a) expand vars/consts before the label and add as argument +# b) expand vars created in the loop body +# """ +# for i,arg in enumerate(args): +# if arg.returns_vector(): +# continue +# if not self.is_vector_arg(i): +# continue +# box_pos, vbox = self.sched_data.getvector_of_box(arg) +# if not vbox: +# # constant/variable expand this box +# vbox = self.expand(arg, i) +# self.sched_data.setvector_of_box(arg, 0, vbox) +# box_pos = 0 +# # convert size i64 -> i32, i32 -> i64, ... +# if self.input_type.getsize() > 0 and \ +# self.input_type.getsize() != vbox.getsize(): +# vbox = self.extend(vbox, self.input_type) + +# # use the input as an indicator for the pack type +# packable = self.input_type.getcount() +# packed = vbox.getcount() +# assert packed >= 0 +# assert packable >= 0 +# if packed > packable: +# # the argument has more items than the operation is able to process! +# # box_pos == 0 then it is already at the right place +# if box_pos != 0: +# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) +# self.update_arg_in_vector_pos(i, args[i]) +# #self.update_input_output(self.pack) +# continue +# else: +# assert vbox is not None +# args[i] = vbox +# continue +# vboxes = self.vector_boxes_for_args(i) +# if packed < packable and len(vboxes) > 1: +# # the argument is scattered along different vector boxes +# args[i] = self.gather(vboxes, packable) +# self.update_arg_in_vector_pos(i, args[i]) +# continue +# if box_pos != 0: +# # The vector box is at a position != 0 but it +# # is required to be at position 0. Unpack it! +# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) +# self.update_arg_in_vector_pos(i, args[i]) +# continue +# #self.update_input_output(self.pack) +# # +# assert vbox is not None +# args[i] = vbox diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -226,12 +226,10 @@ i11 = int_signext(i1, 4) """, additional_args=['v10[2xi64]']) pack1 = self.pack(loop1, 0, 2) - var = self.find_input_arg('v10', loop1) - def i1inv103204(v): - return 0, var + var = loop1.inputargs[-1] loop2 = self.schedule(loop1, [pack1], prepend_invariant=True, overwrite_funcs = { - 'getvector_of_box': i1inv103204, + 'getvector_of_box': lambda v: (0, var), }) loop3 = self.parse_trace(""" v11[2xi32] = vec_int_signext(v10[2xi64], 4) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -734,11 +734,15 @@ def __init__(self, intval=0): self.setint(intval) self.datatype = 'i' + self.bytesize = INT_WORD + self.signed = True class InputArgFloat(FloatOp, AbstractInputArg): def __init__(self, f=longlong.ZEROF): self.setfloatstorage(f) self.datatype = 'f' + self.bytesize = FLOAT_WORD + self.signed = True @staticmethod def fromfloat(x): From noreply at buildbot.pypy.org Tue Sep 15 14:16:40 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 15 Sep 2015 14:16:40 +0200 (CEST) Subject: [pypy-commit] cffi default: Try to be even clearer about when a C compiler is required and when Message-ID: <20150915121640.C6E141C03CF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2270:478fd8ef38b4 Date: 2015-09-15 14:17 +0200 http://bitbucket.org/cffi/cffi/changeset/478fd8ef38b4/ Log: Try to be even clearer about when a C compiler is required and when it is not. diff --git a/doc/source/overview.rst b/doc/source/overview.rst --- a/doc/source/overview.rst +++ b/doc/source/overview.rst @@ -44,6 +44,8 @@ arguments. In the above example it would be ``b"world"`` and ``b"hi there, %s!\n"``. In general it is ``somestring.encode(myencoding)``. +*This example does not call any C compiler.* + .. _out-of-line-abi-level: @@ -58,6 +60,8 @@ ``cdef()`` many times with small pieces of declarations, based on the version of libraries detected on the system). +*This example does not call any C compiler.* + .. code-block:: python # file "simple_example_build.py" @@ -155,6 +159,10 @@ module to generate based on whether the second argument to ``set_source()`` is ``None`` or not.) +*You need a C compiler for this single step. It produces a file called +e.g. _example.so or _example.pyd. If needed, it can be distributed in +precompiled form like any other extension module.* + Then, in your main program, you use: .. code-block:: python @@ -218,6 +226,8 @@ .. _struct: http://docs.python.org/library/struct.html .. _array: http://docs.python.org/library/array.html +*This example does not call any C compiler.* + This example also admits an out-of-line equivalent. It is similar to `Out-of-line example (ABI level, out-of-line)`_ above, but without any call to ``ffi.dlopen()``. In the main program, you write ``from @@ -272,6 +282,10 @@ result = lib.foo(buffer_in, buffer_out, 1000) +*You need a C compiler to run example_build.py, once. It produces a +file called e.g. _example.so or _example.pyd. If needed, it can be +distributed in precompiled form like any other extension module.* + What actually happened? ----------------------- From noreply at buildbot.pypy.org Tue Sep 15 14:48:46 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 15 Sep 2015 14:48:46 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: Merge with 2.6.1 Message-ID: <20150915124846.E8CD61C03CF@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79645:78742c9462e2 Date: 2015-09-15 13:18 +0200 http://bitbucket.org/pypy/pypy/changeset/78742c9462e2/ Log: Merge with 2.6.1 diff too long, truncating to 2000 out of 32878 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -352,8 +353,7 @@ Except when otherwise stated (look for LICENSE files or copyright/license information at the beginning of each file) the files in the 'lib-python/2.7' directory are all copyrighted by the Python Software Foundation and licensed -under the Python Software License of which you can find a copy here: -http://www.python.org/doc/Copyright.html +under the terms that you can find here: https://docs.python.org/2/license.html License for 'pypy/module/unicodedata/' ====================================== @@ -435,4 +435,4 @@ The code is based on gperftools. You may see a copy of the License for it at - https://code.google.com/p/gperftools/source/browse/COPYING + https://github.com/gperftools/gperftools/blob/master/COPYING diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -308,7 +308,10 @@ if (len(data) != 8 or data[:4] != imp.get_magic() or struct.unpack("<@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]" +_LegalKeyChars = r"\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=" +_LegalValueChars = _LegalKeyChars + r"\[\]" _CookiePattern = re.compile( r"(?x)" # This is a Verbose pattern r"\s*" # Optional whitespace at start of cookie r"(?P" # Start of group 'key' - ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy + "["+ _LegalKeyChars +"]+?" # Any word of at least one letter, nongreedy r")" # End of group 'key' r"(" # Optional group: there may not be a value. r"\s*=\s*" # Equal Sign @@ -542,7 +543,7 @@ r"|" # or r"\w{3},\s[\s\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr r"|" # or - ""+ _LegalCharsPatt +"*" # Any word or empty string + "["+ _LegalValueChars +"]*" # Any word or empty string r")" # End of group 'val' r")?" # End of optional value group r"\s*" # Any number of spaces. diff --git a/lib-python/2.7/SimpleHTTPServer.py b/lib-python/2.7/SimpleHTTPServer.py --- a/lib-python/2.7/SimpleHTTPServer.py +++ b/lib-python/2.7/SimpleHTTPServer.py @@ -14,6 +14,7 @@ import posixpath import BaseHTTPServer import urllib +import urlparse import cgi import sys import shutil @@ -68,10 +69,14 @@ path = self.translate_path(self.path) f = None if os.path.isdir(path): - if not self.path.endswith('/'): + parts = urlparse.urlsplit(self.path) + if not parts.path.endswith('/'): # redirect browser - doing basically what apache does self.send_response(301) - self.send_header("Location", self.path + "/") + new_parts = (parts[0], parts[1], parts[2] + '/', + parts[3], parts[4]) + new_url = urlparse.urlunsplit(new_parts) + self.send_header("Location", new_url) self.end_headers() return None for index in "index.html", "index.htm": diff --git a/lib-python/2.7/_LWPCookieJar.py b/lib-python/2.7/_LWPCookieJar.py --- a/lib-python/2.7/_LWPCookieJar.py +++ b/lib-python/2.7/_LWPCookieJar.py @@ -18,7 +18,7 @@ iso2time, time2isoz) def lwp_cookie_str(cookie): - """Return string representation of Cookie in an the LWP cookie file format. + """Return string representation of Cookie in the LWP cookie file format. Actually, the format is extended a bit -- see module docstring. diff --git a/lib-python/2.7/_abcoll.py b/lib-python/2.7/_abcoll.py --- a/lib-python/2.7/_abcoll.py +++ b/lib-python/2.7/_abcoll.py @@ -548,23 +548,25 @@ If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' - if len(args) > 2: - raise TypeError("update() takes at most 2 positional " - "arguments ({} given)".format(len(args))) - elif not args: - raise TypeError("update() takes at least 1 argument (0 given)") + if not args: + raise TypeError("descriptor 'update' of 'MutableMapping' object " + "needs an argument") self = args[0] - other = args[1] if len(args) >= 2 else () - - if isinstance(other, Mapping): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value + args = args[1:] + if len(args) > 1: + raise TypeError('update expected at most 1 arguments, got %d' % + len(args)) + if args: + other = args[0] + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value for key, value in kwds.items(): self[key] = value diff --git a/lib-python/2.7/_pyio.py b/lib-python/2.7/_pyio.py --- a/lib-python/2.7/_pyio.py +++ b/lib-python/2.7/_pyio.py @@ -25,8 +25,8 @@ DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes # NOTE: Base classes defined here are registered with the "official" ABCs -# defined in io.py. We don't use real inheritance though, because we don't -# want to inherit the C implementations. +# defined in io.py. We don't use real inheritance though, because we don't want +# to inherit the C implementations. class BlockingIOError(IOError): @@ -775,7 +775,7 @@ clsname = self.__class__.__name__ try: name = self.name - except AttributeError: + except Exception: return "<_pyio.{0}>".format(clsname) else: return "<_pyio.{0} name={1!r}>".format(clsname, name) @@ -1216,8 +1216,10 @@ return self.writer.flush() def close(self): - self.writer.close() - self.reader.close() + try: + self.writer.close() + finally: + self.reader.close() def isatty(self): return self.reader.isatty() or self.writer.isatty() @@ -1538,7 +1540,7 @@ def __repr__(self): try: name = self.name - except AttributeError: + except Exception: return "<_pyio.TextIOWrapper encoding='{0}'>".format(self.encoding) else: return "<_pyio.TextIOWrapper name={0!r} encoding='{1}'>".format( diff --git a/lib-python/2.7/_strptime.py b/lib-python/2.7/_strptime.py --- a/lib-python/2.7/_strptime.py +++ b/lib-python/2.7/_strptime.py @@ -335,9 +335,9 @@ # though week_of_year = -1 week_of_year_start = -1 - # weekday and julian defaulted to -1 so as to signal need to calculate + # weekday and julian defaulted to None so as to signal need to calculate # values - weekday = julian = -1 + weekday = julian = None found_dict = found.groupdict() for group_key in found_dict.iterkeys(): # Directives not explicitly handled below: @@ -434,14 +434,14 @@ year = 1900 # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year. - if julian == -1 and week_of_year != -1 and weekday != -1: + if julian is None and week_of_year != -1 and weekday is not None: week_starts_Mon = True if week_of_year_start == 0 else False julian = _calc_julian_from_U_or_W(year, week_of_year, weekday, week_starts_Mon) # Cannot pre-calculate datetime_date() since can change in Julian # calculation and thus could have different value for the day of the week # calculation. - if julian == -1: + if julian is None: # Need to add 1 to result since first day of the year is 1, not 0. julian = datetime_date(year, month, day).toordinal() - \ datetime_date(year, 1, 1).toordinal() + 1 @@ -451,7 +451,7 @@ year = datetime_result.year month = datetime_result.month day = datetime_result.day - if weekday == -1: + if weekday is None: weekday = datetime_date(year, month, day).weekday() if leap_year_fix: # the caller didn't supply a year but asked for Feb 29th. We couldn't diff --git a/lib-python/2.7/aifc.py b/lib-python/2.7/aifc.py --- a/lib-python/2.7/aifc.py +++ b/lib-python/2.7/aifc.py @@ -357,10 +357,13 @@ self._soundpos = 0 def close(self): - if self._decomp: - self._decomp.CloseDecompressor() - self._decomp = None - self._file.close() + decomp = self._decomp + try: + if decomp: + self._decomp = None + decomp.CloseDecompressor() + finally: + self._file.close() def tell(self): return self._soundpos diff --git a/lib-python/2.7/binhex.py b/lib-python/2.7/binhex.py --- a/lib-python/2.7/binhex.py +++ b/lib-python/2.7/binhex.py @@ -32,7 +32,8 @@ pass # States (what have we written) -[_DID_HEADER, _DID_DATA, _DID_RSRC] = range(3) +_DID_HEADER = 0 +_DID_DATA = 1 # Various constants REASONABLY_LARGE=32768 # Minimal amount we pass the rle-coder @@ -235,17 +236,22 @@ self._write(data) def close(self): - if self.state < _DID_DATA: - self.close_data() - if self.state != _DID_DATA: - raise Error, 'Close at the wrong time' - if self.rlen != 0: - raise Error, \ - "Incorrect resource-datasize, diff=%r" % (self.rlen,) - self._writecrc() - self.ofp.close() - self.state = None - del self.ofp + if self.state is None: + return + try: + if self.state < _DID_DATA: + self.close_data() + if self.state != _DID_DATA: + raise Error, 'Close at the wrong time' + if self.rlen != 0: + raise Error, \ + "Incorrect resource-datasize, diff=%r" % (self.rlen,) + self._writecrc() + finally: + self.state = None + ofp = self.ofp + del self.ofp + ofp.close() def binhex(inp, out): """(infilename, outfilename) - Create binhex-encoded copy of a file""" @@ -463,11 +469,15 @@ return self._read(n) def close(self): - if self.rlen: - dummy = self.read_rsrc(self.rlen) - self._checkcrc() - self.state = _DID_RSRC - self.ifp.close() + if self.state is None: + return + try: + if self.rlen: + dummy = self.read_rsrc(self.rlen) + self._checkcrc() + finally: + self.state = None + self.ifp.close() def hexbin(inp, out): """(infilename, outfilename) - Decode binhexed file""" diff --git a/lib-python/2.7/bsddb/test/test_all.py b/lib-python/2.7/bsddb/test/test_all.py --- a/lib-python/2.7/bsddb/test/test_all.py +++ b/lib-python/2.7/bsddb/test/test_all.py @@ -412,9 +412,6 @@ def get_dbp(self) : return self._db - import string - string.letters=[chr(i) for i in xrange(65,91)] - bsddb._db.DBEnv_orig = bsddb._db.DBEnv bsddb._db.DB_orig = bsddb._db.DB if bsddb.db.version() <= (4, 3) : diff --git a/lib-python/2.7/bsddb/test/test_basics.py b/lib-python/2.7/bsddb/test/test_basics.py --- a/lib-python/2.7/bsddb/test/test_basics.py +++ b/lib-python/2.7/bsddb/test/test_basics.py @@ -999,7 +999,7 @@ for x in "The quick brown fox jumped over the lazy dog".split(): d2.put(x, self.makeData(x)) - for x in string.letters: + for x in string.ascii_letters: d3.put(x, x*70) d1.sync() @@ -1047,7 +1047,7 @@ if verbose: print rec rec = c3.next() - self.assertEqual(count, len(string.letters)) + self.assertEqual(count, len(string.ascii_letters)) c1.close() diff --git a/lib-python/2.7/bsddb/test/test_dbshelve.py b/lib-python/2.7/bsddb/test/test_dbshelve.py --- a/lib-python/2.7/bsddb/test/test_dbshelve.py +++ b/lib-python/2.7/bsddb/test/test_dbshelve.py @@ -59,7 +59,7 @@ return bytes(key, "iso8859-1") # 8 bits def populateDB(self, d): - for x in string.letters: + for x in string.ascii_letters: d[self.mk('S' + x)] = 10 * x # add a string d[self.mk('I' + x)] = ord(x) # add an integer d[self.mk('L' + x)] = [x] * 10 # add a list diff --git a/lib-python/2.7/bsddb/test/test_get_none.py b/lib-python/2.7/bsddb/test/test_get_none.py --- a/lib-python/2.7/bsddb/test/test_get_none.py +++ b/lib-python/2.7/bsddb/test/test_get_none.py @@ -26,14 +26,14 @@ d.open(self.filename, db.DB_BTREE, db.DB_CREATE) d.set_get_returns_none(1) - for x in string.letters: + for x in string.ascii_letters: d.put(x, x * 40) data = d.get('bad key') self.assertEqual(data, None) - data = d.get(string.letters[0]) - self.assertEqual(data, string.letters[0]*40) + data = d.get(string.ascii_letters[0]) + self.assertEqual(data, string.ascii_letters[0]*40) count = 0 c = d.cursor() @@ -43,7 +43,7 @@ rec = c.next() self.assertEqual(rec, None) - self.assertEqual(count, len(string.letters)) + self.assertEqual(count, len(string.ascii_letters)) c.close() d.close() @@ -54,14 +54,14 @@ d.open(self.filename, db.DB_BTREE, db.DB_CREATE) d.set_get_returns_none(0) - for x in string.letters: + for x in string.ascii_letters: d.put(x, x * 40) self.assertRaises(db.DBNotFoundError, d.get, 'bad key') self.assertRaises(KeyError, d.get, 'bad key') - data = d.get(string.letters[0]) - self.assertEqual(data, string.letters[0]*40) + data = d.get(string.ascii_letters[0]) + self.assertEqual(data, string.ascii_letters[0]*40) count = 0 exceptionHappened = 0 @@ -77,7 +77,7 @@ self.assertNotEqual(rec, None) self.assertTrue(exceptionHappened) - self.assertEqual(count, len(string.letters)) + self.assertEqual(count, len(string.ascii_letters)) c.close() d.close() diff --git a/lib-python/2.7/bsddb/test/test_queue.py b/lib-python/2.7/bsddb/test/test_queue.py --- a/lib-python/2.7/bsddb/test/test_queue.py +++ b/lib-python/2.7/bsddb/test/test_queue.py @@ -10,7 +10,6 @@ #---------------------------------------------------------------------- - at unittest.skip("fails on Windows; see issue 22943") class SimpleQueueTestCase(unittest.TestCase): def setUp(self): self.filename = get_new_database_path() @@ -37,17 +36,17 @@ print "before appends" + '-' * 30 pprint(d.stat()) - for x in string.letters: + for x in string.ascii_letters: d.append(x * 40) - self.assertEqual(len(d), len(string.letters)) + self.assertEqual(len(d), len(string.ascii_letters)) d.put(100, "some more data") d.put(101, "and some more ") d.put(75, "out of order") d.put(1, "replacement data") - self.assertEqual(len(d), len(string.letters)+3) + self.assertEqual(len(d), len(string.ascii_letters)+3) if verbose: print "before close" + '-' * 30 @@ -108,17 +107,17 @@ print "before appends" + '-' * 30 pprint(d.stat()) - for x in string.letters: + for x in string.ascii_letters: d.append(x * 40) - self.assertEqual(len(d), len(string.letters)) + self.assertEqual(len(d), len(string.ascii_letters)) d.put(100, "some more data") d.put(101, "and some more ") d.put(75, "out of order") d.put(1, "replacement data") - self.assertEqual(len(d), len(string.letters)+3) + self.assertEqual(len(d), len(string.ascii_letters)+3) if verbose: print "before close" + '-' * 30 diff --git a/lib-python/2.7/bsddb/test/test_recno.py b/lib-python/2.7/bsddb/test/test_recno.py --- a/lib-python/2.7/bsddb/test/test_recno.py +++ b/lib-python/2.7/bsddb/test/test_recno.py @@ -4,12 +4,11 @@ import os, sys import errno from pprint import pprint +import string import unittest from test_all import db, test_support, verbose, get_new_environment_path, get_new_database_path -letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - #---------------------------------------------------------------------- @@ -39,7 +38,7 @@ d.open(self.filename, db.DB_RECNO, db.DB_CREATE) - for x in letters: + for x in string.ascii_letters: recno = d.append(x * 60) self.assertIsInstance(recno, int) self.assertGreaterEqual(recno, 1) @@ -270,7 +269,7 @@ d.set_re_pad(45) # ...test both int and char d.open(self.filename, db.DB_RECNO, db.DB_CREATE) - for x in letters: + for x in string.ascii_letters: d.append(x * 35) # These will be padded d.append('.' * 40) # this one will be exact diff --git a/lib-python/2.7/chunk.py b/lib-python/2.7/chunk.py --- a/lib-python/2.7/chunk.py +++ b/lib-python/2.7/chunk.py @@ -85,8 +85,10 @@ def close(self): if not self.closed: - self.skip() - self.closed = True + try: + self.skip() + finally: + self.closed = True def isatty(self): if self.closed: diff --git a/lib-python/2.7/codecs.py b/lib-python/2.7/codecs.py --- a/lib-python/2.7/codecs.py +++ b/lib-python/2.7/codecs.py @@ -20,8 +20,14 @@ "BOM_LE", "BOM32_BE", "BOM32_LE", "BOM64_BE", "BOM64_LE", "BOM_UTF8", "BOM_UTF16", "BOM_UTF16_LE", "BOM_UTF16_BE", "BOM_UTF32", "BOM_UTF32_LE", "BOM_UTF32_BE", + "CodecInfo", "Codec", "IncrementalEncoder", "IncrementalDecoder", + "StreamReader", "StreamWriter", + "StreamReaderWriter", "StreamRecoder", + "getencoder", "getdecoder", "getincrementalencoder", + "getincrementaldecoder", "getreader", "getwriter", + "encode", "decode", "iterencode", "iterdecode", "strict_errors", "ignore_errors", "replace_errors", - "xmlcharrefreplace_errors", + "xmlcharrefreplace_errors", "backslashreplace_errors", "register_error", "lookup_error"] ### Constants @@ -1051,7 +1057,7 @@ during translation. One example where this happens is cp875.py which decodes - multiple character to \u001a. + multiple character to \\u001a. """ m = {} diff --git a/lib-python/2.7/collections.py b/lib-python/2.7/collections.py --- a/lib-python/2.7/collections.py +++ b/lib-python/2.7/collections.py @@ -330,7 +330,7 @@ # http://code.activestate.com/recipes/259174/ # Knuth, TAOCP Vol. II section 4.6.3 - def __init__(self, iterable=None, **kwds): + def __init__(*args, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. @@ -341,8 +341,15 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' + if not args: + raise TypeError("descriptor '__init__' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) super(Counter, self).__init__() - self.update(iterable, **kwds) + self.update(*args, **kwds) def __missing__(self, key): 'The count of elements not in the Counter is zero.' @@ -393,7 +400,7 @@ raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') - def update(self, iterable=None, **kwds): + def update(*args, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. @@ -413,6 +420,14 @@ # contexts. Instead, we implement straight-addition. Both the inputs # and outputs are allowed to contain zero and negative counts. + if not args: + raise TypeError("descriptor 'update' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: if isinstance(iterable, Mapping): if self: @@ -428,7 +443,7 @@ if kwds: self.update(kwds) - def subtract(self, iterable=None, **kwds): + def subtract(*args, **kwds): '''Like dict.update() but subtracts counts instead of replacing them. Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts. @@ -444,6 +459,14 @@ -1 ''' + if not args: + raise TypeError("descriptor 'subtract' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: self_get = self.get if isinstance(iterable, Mapping): diff --git a/lib-python/2.7/cookielib.py b/lib-python/2.7/cookielib.py --- a/lib-python/2.7/cookielib.py +++ b/lib-python/2.7/cookielib.py @@ -464,26 +464,42 @@ for ns_header in ns_headers: pairs = [] version_set = False - for ii, param in enumerate(re.split(r";\s*", ns_header)): - param = param.rstrip() - if param == "": continue - if "=" not in param: - k, v = param, None - else: - k, v = re.split(r"\s*=\s*", param, 1) - k = k.lstrip() + + # XXX: The following does not strictly adhere to RFCs in that empty + # names and values are legal (the former will only appear once and will + # be overwritten if multiple occurrences are present). This is + # mostly to deal with backwards compatibility. + for ii, param in enumerate(ns_header.split(';')): + param = param.strip() + + key, sep, val = param.partition('=') + key = key.strip() + + if not key: + if ii == 0: + break + else: + continue + + # allow for a distinction between present and empty and missing + # altogether + val = val.strip() if sep else None + if ii != 0: - lc = k.lower() + lc = key.lower() if lc in known_attrs: - k = lc - if k == "version": + key = lc + + if key == "version": # This is an RFC 2109 cookie. - v = _strip_quotes(v) + if val is not None: + val = _strip_quotes(val) version_set = True - if k == "expires": + elif key == "expires": # convert expires date to seconds since epoch - v = http2time(_strip_quotes(v)) # None if invalid - pairs.append((k, v)) + if val is not None: + val = http2time(_strip_quotes(val)) # None if invalid + pairs.append((key, val)) if pairs: if not version_set: diff --git a/lib-python/2.7/ctypes/macholib/fetch_macholib.bat b/lib-python/2.7/ctypes/macholib/fetch_macholib.bat --- a/lib-python/2.7/ctypes/macholib/fetch_macholib.bat +++ b/lib-python/2.7/ctypes/macholib/fetch_macholib.bat @@ -1,1 +1,1 @@ -svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ . +svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ . diff --git a/lib-python/2.7/ctypes/test/test_find.py b/lib-python/2.7/ctypes/test/test_find.py --- a/lib-python/2.7/ctypes/test/test_find.py +++ b/lib-python/2.7/ctypes/test/test_find.py @@ -32,15 +32,24 @@ def setUp(self): self.gl = self.glu = self.gle = None if lib_gl: - self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) + try: + self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) + except OSError: + pass if lib_glu: - self.glu = CDLL(lib_glu, RTLD_GLOBAL) + try: + self.glu = CDLL(lib_glu, RTLD_GLOBAL) + except OSError: + pass if lib_gle: try: self.gle = CDLL(lib_gle) except OSError: pass + def tearDown(self): + self.gl = self.glu = self.gle = None + @unittest.skipUnless(lib_gl, 'lib_gl not available') def test_gl(self): if self.gl: diff --git a/lib-python/2.7/ctypes/test/test_pickling.py b/lib-python/2.7/ctypes/test/test_pickling.py --- a/lib-python/2.7/ctypes/test/test_pickling.py +++ b/lib-python/2.7/ctypes/test/test_pickling.py @@ -15,9 +15,9 @@ class Y(X): _fields_ = [("str", c_char_p)] -class PickleTest(unittest.TestCase): +class PickleTest: def dumps(self, item): - return pickle.dumps(item) + return pickle.dumps(item, self.proto) def loads(self, item): return pickle.loads(item) @@ -72,17 +72,15 @@ @xfail def test_wchar(self): - pickle.dumps(c_char("x")) + self.dumps(c_char(b"x")) # Issue 5049 - pickle.dumps(c_wchar(u"x")) + self.dumps(c_wchar(u"x")) -class PickleTest_1(PickleTest): - def dumps(self, item): - return pickle.dumps(item, 1) - -class PickleTest_2(PickleTest): - def dumps(self, item): - return pickle.dumps(item, 2) +for proto in range(pickle.HIGHEST_PROTOCOL + 1): + name = 'PickleTest_%s' % proto + globals()[name] = type(name, + (PickleTest, unittest.TestCase), + {'proto': proto}) if __name__ == "__main__": unittest.main() diff --git a/lib-python/2.7/ctypes/test/test_pointers.py b/lib-python/2.7/ctypes/test/test_pointers.py --- a/lib-python/2.7/ctypes/test/test_pointers.py +++ b/lib-python/2.7/ctypes/test/test_pointers.py @@ -7,8 +7,6 @@ c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float] python_types = [int, int, int, int, int, long, int, long, long, long, float, float] -LargeNamedType = type('T' * 2 ** 25, (Structure,), {}) -large_string = 'T' * 2 ** 25 class PointersTestCase(unittest.TestCase): @@ -191,9 +189,11 @@ self.assertEqual(bool(mth), True) def test_pointer_type_name(self): + LargeNamedType = type('T' * 2 ** 25, (Structure,), {}) self.assertTrue(POINTER(LargeNamedType)) def test_pointer_type_str_name(self): + large_string = 'T' * 2 ** 25 self.assertTrue(POINTER(large_string)) if __name__ == '__main__': diff --git a/lib-python/2.7/ctypes/util.py b/lib-python/2.7/ctypes/util.py --- a/lib-python/2.7/ctypes/util.py +++ b/lib-python/2.7/ctypes/util.py @@ -178,7 +178,7 @@ res = re.findall(expr, data) if not res: return _get_soname(_findLib_gcc(name)) - res.sort(cmp= lambda x,y: cmp(_num_version(x), _num_version(y))) + res.sort(key=_num_version) return res[-1] elif sys.platform == "sunos5": diff --git a/lib-python/2.7/distutils/__init__.py b/lib-python/2.7/distutils/__init__.py --- a/lib-python/2.7/distutils/__init__.py +++ b/lib-python/2.7/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "2.7.9" +__version__ = "2.7.10" #--end constants-- diff --git a/lib-python/2.7/distutils/command/check.py b/lib-python/2.7/distutils/command/check.py --- a/lib-python/2.7/distutils/command/check.py +++ b/lib-python/2.7/distutils/command/check.py @@ -126,7 +126,7 @@ """Returns warnings when the provided data doesn't compile.""" source_path = StringIO() parser = Parser() - settings = frontend.OptionParser().get_default_values() + settings = frontend.OptionParser(components=(Parser,)).get_default_values() settings.tab_width = 4 settings.pep_references = None settings.rfc_references = None @@ -142,8 +142,8 @@ document.note_source(source_path, -1) try: parser.parse(data, document) - except AttributeError: - reporter.messages.append((-1, 'Could not finish the parsing.', - '', {})) + except AttributeError as e: + reporter.messages.append( + (-1, 'Could not finish the parsing: %s.' % e, '', {})) return reporter.messages diff --git a/lib-python/2.7/distutils/dir_util.py b/lib-python/2.7/distutils/dir_util.py --- a/lib-python/2.7/distutils/dir_util.py +++ b/lib-python/2.7/distutils/dir_util.py @@ -83,7 +83,7 @@ """Create all the empty directories under 'base_dir' needed to put 'files' there. - 'base_dir' is just the a name of a directory which doesn't necessarily + 'base_dir' is just the name of a directory which doesn't necessarily exist yet; 'files' is a list of filenames to be interpreted relative to 'base_dir'. 'base_dir' + the directory portion of every file in 'files' will be created if it doesn't already exist. 'mode', 'verbose' and diff --git a/lib-python/2.7/distutils/tests/test_check.py b/lib-python/2.7/distutils/tests/test_check.py --- a/lib-python/2.7/distutils/tests/test_check.py +++ b/lib-python/2.7/distutils/tests/test_check.py @@ -1,5 +1,6 @@ # -*- encoding: utf8 -*- """Tests for distutils.command.check.""" +import textwrap import unittest from test.test_support import run_unittest @@ -93,6 +94,36 @@ cmd = self._run(metadata, strict=1, restructuredtext=1) self.assertEqual(cmd._warnings, 0) + @unittest.skipUnless(HAS_DOCUTILS, "won't test without docutils") + def test_check_restructuredtext_with_syntax_highlight(self): + # Don't fail if there is a `code` or `code-block` directive + + example_rst_docs = [] + example_rst_docs.append(textwrap.dedent("""\ + Here's some code: + + .. code:: python + + def foo(): + pass + """)) + example_rst_docs.append(textwrap.dedent("""\ + Here's some code: + + .. code-block:: python + + def foo(): + pass + """)) + + for rest_with_code in example_rst_docs: + pkg_info, dist = self.create_dist(long_description=rest_with_code) + cmd = check(dist) + cmd.check_restructuredtext() + self.assertEqual(cmd._warnings, 0) + msgs = cmd._check_rst_data(rest_with_code) + self.assertEqual(len(msgs), 0) + def test_check_all(self): metadata = {'url': 'xxx', 'author': 'xxx'} diff --git a/lib-python/2.7/distutils/text_file.py b/lib-python/2.7/distutils/text_file.py --- a/lib-python/2.7/distutils/text_file.py +++ b/lib-python/2.7/distutils/text_file.py @@ -124,11 +124,11 @@ def close (self): """Close the current file and forget everything we know about it (filename, current line number).""" - - self.file.close () + file = self.file self.file = None self.filename = None self.current_line = None + file.close() def gen_error (self, msg, line=None): diff --git a/lib-python/2.7/dumbdbm.py b/lib-python/2.7/dumbdbm.py --- a/lib-python/2.7/dumbdbm.py +++ b/lib-python/2.7/dumbdbm.py @@ -21,6 +21,7 @@ """ +import ast as _ast import os as _os import __builtin__ import UserDict @@ -85,7 +86,7 @@ with f: for line in f: line = line.rstrip() - key, pos_and_siz_pair = eval(line) + key, pos_and_siz_pair = _ast.literal_eval(line) self._index[key] = pos_and_siz_pair # Write the index dict to the directory file. The original directory @@ -208,8 +209,10 @@ return len(self._index) def close(self): - self._commit() - self._index = self._datfile = self._dirfile = self._bakfile = None + try: + self._commit() + finally: + self._index = self._datfile = self._dirfile = self._bakfile = None __del__ = close diff --git a/lib-python/2.7/encodings/uu_codec.py b/lib-python/2.7/encodings/uu_codec.py --- a/lib-python/2.7/encodings/uu_codec.py +++ b/lib-python/2.7/encodings/uu_codec.py @@ -84,7 +84,7 @@ data = a2b_uu(s) except binascii.Error, v: # Workaround for broken uuencoders by /Fredrik Lundh - nbytes = (((ord(s[0])-32) & 63) * 4 + 5) / 3 + nbytes = (((ord(s[0])-32) & 63) * 4 + 5) // 3 data = a2b_uu(s[:nbytes]) #sys.stderr.write("Warning: %s\n" % str(v)) write(data) diff --git a/lib-python/2.7/ensurepip/__init__.py b/lib-python/2.7/ensurepip/__init__.py --- a/lib-python/2.7/ensurepip/__init__.py +++ b/lib-python/2.7/ensurepip/__init__.py @@ -12,9 +12,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "7.0" +_SETUPTOOLS_VERSION = "15.2" -_PIP_VERSION = "1.5.6" +_PIP_VERSION = "6.1.1" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/lib-python/2.7/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl deleted file mode 100644 Binary file lib-python/2.7/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl has changed diff --git a/lib-python/2.7/ensurepip/_bundled/pip-6.1.1-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/pip-6.1.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..e59694a019051d58b9a378a1adfc9461b8cec9c3 GIT binary patch [cut] diff --git a/lib-python/2.7/ensurepip/_bundled/setuptools-15.2-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/setuptools-15.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..f153ed376684275e08fcfebdb2de8352fb074171 GIT binary patch [cut] diff --git a/lib-python/2.7/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl b/lib-python/2.7/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl deleted file mode 100644 Binary file lib-python/2.7/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl has changed diff --git a/lib-python/2.7/fileinput.py b/lib-python/2.7/fileinput.py --- a/lib-python/2.7/fileinput.py +++ b/lib-python/2.7/fileinput.py @@ -233,8 +233,10 @@ self.close() def close(self): - self.nextfile() - self._files = () + try: + self.nextfile() + finally: + self._files = () def __iter__(self): return self @@ -270,23 +272,25 @@ output = self._output self._output = 0 - if output: - output.close() + try: + if output: + output.close() + finally: + file = self._file + self._file = 0 + try: + if file and not self._isstdin: + file.close() + finally: + backupfilename = self._backupfilename + self._backupfilename = 0 + if backupfilename and not self._backup: + try: os.unlink(backupfilename) + except OSError: pass - file = self._file - self._file = 0 - if file and not self._isstdin: - file.close() - - backupfilename = self._backupfilename - self._backupfilename = 0 - if backupfilename and not self._backup: - try: os.unlink(backupfilename) - except OSError: pass - - self._isstdin = False - self._buffer = [] - self._bufindex = 0 + self._isstdin = False + self._buffer = [] + self._bufindex = 0 def readline(self): try: diff --git a/lib-python/2.7/fnmatch.py b/lib-python/2.7/fnmatch.py --- a/lib-python/2.7/fnmatch.py +++ b/lib-python/2.7/fnmatch.py @@ -47,12 +47,14 @@ import os,posixpath result=[] pat=os.path.normcase(pat) - if not pat in _cache: + try: + re_pat = _cache[pat] + except KeyError: res = translate(pat) if len(_cache) >= _MAXCACHE: _cache.clear() - _cache[pat] = re.compile(res) - match=_cache[pat].match + _cache[pat] = re_pat = re.compile(res) + match = re_pat.match if os.path is posixpath: # normcase on posix is NOP. Optimize it away from the loop. for name in names: @@ -71,12 +73,14 @@ its arguments. """ - if not pat in _cache: + try: + re_pat = _cache[pat] + except KeyError: res = translate(pat) if len(_cache) >= _MAXCACHE: _cache.clear() - _cache[pat] = re.compile(res) - return _cache[pat].match(name) is not None + _cache[pat] = re_pat = re.compile(res) + return re_pat.match(name) is not None def translate(pat): """Translate a shell PATTERN to a regular expression. diff --git a/lib-python/2.7/ftplib.py b/lib-python/2.7/ftplib.py --- a/lib-python/2.7/ftplib.py +++ b/lib-python/2.7/ftplib.py @@ -594,11 +594,16 @@ def close(self): '''Close the connection without assuming anything about it.''' - if self.file is not None: - self.file.close() - if self.sock is not None: - self.sock.close() - self.file = self.sock = None + try: + file = self.file + self.file = None + if file is not None: + file.close() + finally: + sock = self.sock + self.sock = None + if sock is not None: + sock.close() try: import ssl @@ -638,12 +643,24 @@ '221 Goodbye.' >>> ''' - ssl_version = ssl.PROTOCOL_TLSv1 + ssl_version = ssl.PROTOCOL_SSLv23 def __init__(self, host='', user='', passwd='', acct='', keyfile=None, - certfile=None, timeout=_GLOBAL_DEFAULT_TIMEOUT): + certfile=None, context=None, + timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None): + if context is not None and keyfile is not None: + raise ValueError("context and keyfile arguments are mutually " + "exclusive") + if context is not None and certfile is not None: + raise ValueError("context and certfile arguments are mutually " + "exclusive") self.keyfile = keyfile self.certfile = certfile + if context is None: + context = ssl._create_stdlib_context(self.ssl_version, + certfile=certfile, + keyfile=keyfile) + self.context = context self._prot_p = False FTP.__init__(self, host, user, passwd, acct, timeout) @@ -656,12 +673,12 @@ '''Set up secure control connection by using TLS/SSL.''' if isinstance(self.sock, ssl.SSLSocket): raise ValueError("Already using TLS") - if self.ssl_version == ssl.PROTOCOL_TLSv1: + if self.ssl_version >= ssl.PROTOCOL_SSLv23: resp = self.voidcmd('AUTH TLS') else: resp = self.voidcmd('AUTH SSL') - self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, - ssl_version=self.ssl_version) + self.sock = self.context.wrap_socket(self.sock, + server_hostname=self.host) self.file = self.sock.makefile(mode='rb') return resp @@ -692,8 +709,8 @@ def ntransfercmd(self, cmd, rest=None): conn, size = FTP.ntransfercmd(self, cmd, rest) if self._prot_p: - conn = ssl.wrap_socket(conn, self.keyfile, self.certfile, - ssl_version=self.ssl_version) + conn = self.context.wrap_socket(conn, + server_hostname=self.host) return conn, size def retrbinary(self, cmd, callback, blocksize=8192, rest=None): diff --git a/lib-python/2.7/genericpath.py b/lib-python/2.7/genericpath.py --- a/lib-python/2.7/genericpath.py +++ b/lib-python/2.7/genericpath.py @@ -10,6 +10,14 @@ 'getsize', 'isdir', 'isfile'] +try: + _unicode = unicode +except NameError: + # If Python is built without Unicode support, the unicode type + # will not exist. Fake one. + class _unicode(object): + pass + # Does a path exist? # This is false for dangling symbolic links on systems that support them. def exists(path): diff --git a/lib-python/2.7/gettext.py b/lib-python/2.7/gettext.py --- a/lib-python/2.7/gettext.py +++ b/lib-python/2.7/gettext.py @@ -52,7 +52,9 @@ __all__ = ['NullTranslations', 'GNUTranslations', 'Catalog', 'find', 'translation', 'install', 'textdomain', 'bindtextdomain', - 'dgettext', 'dngettext', 'gettext', 'ngettext', + 'bind_textdomain_codeset', + 'dgettext', 'dngettext', 'gettext', 'lgettext', 'ldgettext', + 'ldngettext', 'lngettext', 'ngettext', ] _default_localedir = os.path.join(sys.prefix, 'share', 'locale') @@ -294,11 +296,12 @@ # See if we're looking at GNU .mo conventions for metadata if mlen == 0: # Catalog description - lastk = k = None + lastk = None for item in tmsg.splitlines(): item = item.strip() if not item: continue + k = v = None if ':' in item: k, v = item.split(':', 1) k = k.strip().lower() diff --git a/lib-python/2.7/gzip.py b/lib-python/2.7/gzip.py --- a/lib-python/2.7/gzip.py +++ b/lib-python/2.7/gzip.py @@ -238,9 +238,9 @@ data = data.tobytes() if len(data) > 0: - self.size = self.size + len(data) + self.fileobj.write(self.compress.compress(data)) + self.size += len(data) self.crc = zlib.crc32(data, self.crc) & 0xffffffffL - self.fileobj.write( self.compress.compress(data) ) self.offset += len(data) return len(data) @@ -369,19 +369,21 @@ return self.fileobj is None def close(self): - if self.fileobj is None: + fileobj = self.fileobj + if fileobj is None: return - if self.mode == WRITE: - self.fileobj.write(self.compress.flush()) - write32u(self.fileobj, self.crc) - # self.size may exceed 2GB, or even 4GB - write32u(self.fileobj, self.size & 0xffffffffL) - self.fileobj = None - elif self.mode == READ: - self.fileobj = None - if self.myfileobj: - self.myfileobj.close() - self.myfileobj = None + self.fileobj = None + try: + if self.mode == WRITE: + fileobj.write(self.compress.flush()) + write32u(fileobj, self.crc) + # self.size may exceed 2GB, or even 4GB + write32u(fileobj, self.size & 0xffffffffL) + finally: + myfileobj = self.myfileobj + if myfileobj: + self.myfileobj = None + myfileobj.close() def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH): self._check_closed() diff --git a/lib-python/2.7/hashlib.py b/lib-python/2.7/hashlib.py --- a/lib-python/2.7/hashlib.py +++ b/lib-python/2.7/hashlib.py @@ -187,7 +187,7 @@ def prf(msg, inner=inner, outer=outer): # PBKDF2_HMAC uses the password as key. We can re-use the same - # digest objects and and just update copies to skip initialization. + # digest objects and just update copies to skip initialization. icpy = inner.copy() ocpy = outer.copy() icpy.update(msg) diff --git a/lib-python/2.7/htmlentitydefs.py b/lib-python/2.7/htmlentitydefs.py --- a/lib-python/2.7/htmlentitydefs.py +++ b/lib-python/2.7/htmlentitydefs.py @@ -1,6 +1,6 @@ """HTML character entity references.""" -# maps the HTML entity name to the Unicode codepoint +# maps the HTML entity name to the Unicode code point name2codepoint = { 'AElig': 0x00c6, # latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 'Aacute': 0x00c1, # latin capital letter A with acute, U+00C1 ISOlat1 @@ -256,7 +256,7 @@ 'zwnj': 0x200c, # zero width non-joiner, U+200C NEW RFC 2070 } -# maps the Unicode codepoint to the HTML entity name +# maps the Unicode code point to the HTML entity name codepoint2name = {} # maps the HTML entity name to the character diff --git a/lib-python/2.7/httplib.py b/lib-python/2.7/httplib.py --- a/lib-python/2.7/httplib.py +++ b/lib-python/2.7/httplib.py @@ -68,6 +68,7 @@ from array import array import os +import re import socket from sys import py3kwarning from urlparse import urlsplit @@ -218,6 +219,38 @@ # maximum amount of headers accepted _MAXHEADERS = 100 +# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) +# +# VCHAR = %x21-7E +# obs-text = %x80-FF +# header-field = field-name ":" OWS field-value OWS +# field-name = token +# field-value = *( field-content / obs-fold ) +# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +# field-vchar = VCHAR / obs-text +# +# obs-fold = CRLF 1*( SP / HTAB ) +# ; obsolete line folding +# ; see Section 3.2.4 + +# token = 1*tchar +# +# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +# / DIGIT / ALPHA +# ; any VCHAR, except delimiters +# +# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 + +# the patterns for both name and value are more leniant than RFC +# definitions to allow for backwards compatibility +_is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match +_is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search + +# We always set the Content-Length header for these methods because some +# servers will otherwise respond with a 411 +_METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'} + class HTTPMessage(mimetools.Message): @@ -313,6 +346,11 @@ hlist.append(line) self.addheader(headerseen, line[len(headerseen)+1:].strip()) continue + elif headerseen is not None: + # An empty header name. These aren't allowed in HTTP, but it's + # probably a benign mistake. Don't add the header, just keep + # going. + continue else: # It's not a header line; throw it back and stop here. if not self.dict: @@ -522,9 +560,10 @@ return True def close(self): - if self.fp: - self.fp.close() + fp = self.fp + if fp: self.fp = None + fp.close() def isclosed(self): # NOTE: it is possible that we will not ever call self.close(). This @@ -723,7 +762,7 @@ endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT request to the proxy server when the connection is established. - This method must be called before the HTML connection has been + This method must be called before the HTTP connection has been established. The headers argument should be a mapping of extra HTTP headers @@ -797,13 +836,17 @@ def close(self): """Close the connection to the HTTP server.""" - if self.sock: - self.sock.close() # close it manually... there may be other refs - self.sock = None - if self.__response: - self.__response.close() - self.__response = None self.__state = _CS_IDLE + try: + sock = self.sock + if sock: + self.sock = None + sock.close() # close it manually... there may be other refs + finally: + response = self.__response + if response: + self.__response = None + response.close() def send(self, data): """Send `data' to the server.""" @@ -978,7 +1021,16 @@ if self.__state != _CS_REQ_STARTED: raise CannotSendHeader() - hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values])) + header = '%s' % header + if not _is_legal_header_name(header): + raise ValueError('Invalid header name %r' % (header,)) + + values = [str(v) for v in values] + for one_value in values: + if _is_illegal_header_value(one_value): + raise ValueError('Invalid header value %r' % (one_value,)) + + hdr = '%s: %s' % (header, '\r\n\t'.join(values)) self._output(hdr) def endheaders(self, message_body=None): @@ -1000,19 +1052,25 @@ """Send a complete request to the server.""" self._send_request(method, url, body, headers) - def _set_content_length(self, body): - # Set the content-length based on the body. + def _set_content_length(self, body, method): + # Set the content-length based on the body. If the body is "empty", we + # set Content-Length: 0 for methods that expect a body (RFC 7230, + # Section 3.3.2). If the body is set for other methods, we set the + # header provided we can figure out what the length is. thelen = None - try: - thelen = str(len(body)) - except TypeError, te: - # If this is a file-like object, try to - # fstat its file descriptor + if body is None and method.upper() in _METHODS_EXPECTING_BODY: + thelen = '0' + elif body is not None: try: - thelen = str(os.fstat(body.fileno()).st_size) - except (AttributeError, OSError): - # Don't send a length if this failed - if self.debuglevel > 0: print "Cannot stat!!" + thelen = str(len(body)) + except TypeError: + # If this is a file-like object, try to + # fstat its file descriptor + try: + thelen = str(os.fstat(body.fileno()).st_size) + except (AttributeError, OSError): + # Don't send a length if this failed + if self.debuglevel > 0: print "Cannot stat!!" if thelen is not None: self.putheader('Content-Length', thelen) @@ -1028,8 +1086,8 @@ self.putrequest(method, url, **skips) - if body is not None and 'content-length' not in header_names: - self._set_content_length(body) + if 'content-length' not in header_names: + self._set_content_length(body, method) for hdr, value in headers.iteritems(): self.putheader(hdr, value) self.endheaders(body) @@ -1072,20 +1130,20 @@ try: response.begin() + assert response.will_close != _UNKNOWN + self.__state = _CS_IDLE + + if response.will_close: + # this effectively passes the connection to the response + self.close() + else: + # remember this, so we can tell when it is complete + self.__response = response + + return response except: response.close() raise - assert response.will_close != _UNKNOWN - self.__state = _CS_IDLE - - if response.will_close: - # this effectively passes the connection to the response - self.close() - else: - # remember this, so we can tell when it is complete - self.__response = response - - return response class HTTP: @@ -1129,7 +1187,7 @@ "Accept arguments to set the host/port, since the superclass doesn't." if host is not None: - self._conn._set_hostport(host, port) + (self._conn.host, self._conn.port) = self._conn._get_hostport(host, port) self._conn.connect() def getfile(self): diff --git a/lib-python/2.7/idlelib/CodeContext.py b/lib-python/2.7/idlelib/CodeContext.py --- a/lib-python/2.7/idlelib/CodeContext.py +++ b/lib-python/2.7/idlelib/CodeContext.py @@ -15,8 +15,8 @@ from sys import maxint as INFINITY from idlelib.configHandler import idleConf -BLOCKOPENERS = set(["class", "def", "elif", "else", "except", "finally", "for", - "if", "try", "while", "with"]) +BLOCKOPENERS = {"class", "def", "elif", "else", "except", "finally", "for", + "if", "try", "while", "with"} UPDATEINTERVAL = 100 # millisec FONTUPDATEINTERVAL = 1000 # millisec diff --git a/lib-python/2.7/idlelib/EditorWindow.py b/lib-python/2.7/idlelib/EditorWindow.py --- a/lib-python/2.7/idlelib/EditorWindow.py +++ b/lib-python/2.7/idlelib/EditorWindow.py @@ -469,13 +469,10 @@ ("format", "F_ormat"), ("run", "_Run"), ("options", "_Options"), - ("windows", "_Windows"), + ("windows", "_Window"), ("help", "_Help"), ] - if sys.platform == "darwin": - menu_specs[-2] = ("windows", "_Window") - def createmenubar(self): mbar = self.menubar diff --git a/lib-python/2.7/idlelib/FormatParagraph.py b/lib-python/2.7/idlelib/FormatParagraph.py --- a/lib-python/2.7/idlelib/FormatParagraph.py +++ b/lib-python/2.7/idlelib/FormatParagraph.py @@ -44,9 +44,11 @@ The length limit parameter is for testing with a known value. """ - if limit == None: + if limit is None: + # The default length limit is that defined by pep8 limit = idleConf.GetOption( - 'main', 'FormatParagraph', 'paragraph', type='int') + 'extensions', 'FormatParagraph', 'max-width', + type='int', default=72) text = self.editwin.text first, last = self.editwin.get_selection_indices() if first and last: diff --git a/lib-python/2.7/idlelib/PyShell.py b/lib-python/2.7/idlelib/PyShell.py --- a/lib-python/2.7/idlelib/PyShell.py +++ b/lib-python/2.7/idlelib/PyShell.py @@ -871,13 +871,10 @@ ("edit", "_Edit"), ("debug", "_Debug"), ("options", "_Options"), - ("windows", "_Windows"), + ("windows", "_Window"), ("help", "_Help"), ] - if sys.platform == "darwin": - menu_specs[-2] = ("windows", "_Window") - # New classes from idlelib.IdleHistory import History @@ -1350,7 +1347,7 @@ if type(s) not in (unicode, str, bytearray): # See issue #19481 if isinstance(s, unicode): - s = unicode.__getslice__(s, None, None) + s = unicode.__getitem__(s, slice(None)) elif isinstance(s, str): s = str.__str__(s) elif isinstance(s, bytearray): diff --git a/lib-python/2.7/idlelib/SearchEngine.py b/lib-python/2.7/idlelib/SearchEngine.py --- a/lib-python/2.7/idlelib/SearchEngine.py +++ b/lib-python/2.7/idlelib/SearchEngine.py @@ -191,7 +191,7 @@ This is done by searching forwards until there is no match. Prog: compiled re object with a search method returning a match. - Chars: line of text, without \n. + Chars: line of text, without \\n. Col: stop index for the search; the limit for match.end(). ''' m = prog.search(chars) diff --git a/lib-python/2.7/idlelib/config-extensions.def b/lib-python/2.7/idlelib/config-extensions.def --- a/lib-python/2.7/idlelib/config-extensions.def +++ b/lib-python/2.7/idlelib/config-extensions.def @@ -66,6 +66,7 @@ [FormatParagraph] enable=True +max-width=72 [FormatParagraph_cfgBindings] format-paragraph= diff --git a/lib-python/2.7/idlelib/config-main.def b/lib-python/2.7/idlelib/config-main.def --- a/lib-python/2.7/idlelib/config-main.def +++ b/lib-python/2.7/idlelib/config-main.def @@ -58,9 +58,6 @@ font-bold= 0 encoding= none -[FormatParagraph] -paragraph=72 - [Indent] use-spaces= 1 num-spaces= 4 diff --git a/lib-python/2.7/idlelib/configDialog.py b/lib-python/2.7/idlelib/configDialog.py --- a/lib-python/2.7/idlelib/configDialog.py +++ b/lib-python/2.7/idlelib/configDialog.py @@ -371,7 +371,6 @@ parent = self.parent self.winWidth = StringVar(parent) self.winHeight = StringVar(parent) - self.paraWidth = StringVar(parent) self.startupEdit = IntVar(parent) self.autoSave = IntVar(parent) self.encoding = StringVar(parent) @@ -387,7 +386,6 @@ frameSave = LabelFrame(frame, borderwidth=2, relief=GROOVE, text=' Autosave Preferences ') frameWinSize = Frame(frame, borderwidth=2, relief=GROOVE) - frameParaSize = Frame(frame, borderwidth=2, relief=GROOVE) frameEncoding = Frame(frame, borderwidth=2, relief=GROOVE) frameHelp = LabelFrame(frame, borderwidth=2, relief=GROOVE, text=' Additional Help Sources ') @@ -416,11 +414,6 @@ labelWinHeightTitle = Label(frameWinSize, text='Height') entryWinHeight = Entry( frameWinSize, textvariable=self.winHeight, width=3) - #paragraphFormatWidth - labelParaWidthTitle = Label( - frameParaSize, text='Paragraph reformat width (in characters)') - entryParaWidth = Entry( - frameParaSize, textvariable=self.paraWidth, width=3) #frameEncoding labelEncodingTitle = Label( frameEncoding, text="Default Source Encoding") @@ -458,7 +451,6 @@ frameRun.pack(side=TOP, padx=5, pady=5, fill=X) frameSave.pack(side=TOP, padx=5, pady=5, fill=X) frameWinSize.pack(side=TOP, padx=5, pady=5, fill=X) - frameParaSize.pack(side=TOP, padx=5, pady=5, fill=X) frameEncoding.pack(side=TOP, padx=5, pady=5, fill=X) frameHelp.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH) #frameRun @@ -475,9 +467,6 @@ labelWinHeightTitle.pack(side=RIGHT, anchor=E, pady=5) entryWinWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5) labelWinWidthTitle.pack(side=RIGHT, anchor=E, pady=5) - #paragraphFormatWidth - labelParaWidthTitle.pack(side=LEFT, anchor=W, padx=5, pady=5) - entryParaWidth.pack(side=RIGHT, anchor=E, padx=10, pady=5) #frameEncoding labelEncodingTitle.pack(side=LEFT, anchor=W, padx=5, pady=5) radioEncNone.pack(side=RIGHT, anchor=E, pady=5) @@ -509,7 +498,6 @@ self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin) self.winWidth.trace_variable('w', self.VarChanged_winWidth) self.winHeight.trace_variable('w', self.VarChanged_winHeight) - self.paraWidth.trace_variable('w', self.VarChanged_paraWidth) self.startupEdit.trace_variable('w', self.VarChanged_startupEdit) self.autoSave.trace_variable('w', self.VarChanged_autoSave) self.encoding.trace_variable('w', self.VarChanged_encoding) @@ -594,10 +582,6 @@ value = self.winHeight.get() self.AddChangedItem('main', 'EditorWindow', 'height', value) - def VarChanged_paraWidth(self, *params): - value = self.paraWidth.get() - self.AddChangedItem('main', 'FormatParagraph', 'paragraph', value) - def VarChanged_startupEdit(self, *params): value = self.startupEdit.get() self.AddChangedItem('main', 'General', 'editor-on-startup', value) @@ -1094,9 +1078,6 @@ 'main', 'EditorWindow', 'width', type='int')) self.winHeight.set(idleConf.GetOption( 'main', 'EditorWindow', 'height', type='int')) - #initial paragraph reformat size - self.paraWidth.set(idleConf.GetOption( - 'main', 'FormatParagraph', 'paragraph', type='int')) # default source encoding self.encoding.set(idleConf.GetOption( 'main', 'EditorWindow', 'encoding', default='none')) diff --git a/lib-python/2.7/idlelib/help.txt b/lib-python/2.7/idlelib/help.txt --- a/lib-python/2.7/idlelib/help.txt +++ b/lib-python/2.7/idlelib/help.txt @@ -100,7 +100,7 @@ which is scrolling off the top or the window. (Not present in Shell window.) -Windows Menu: +Window Menu: Zoom Height -- toggles the window between configured size and maximum height. diff --git a/lib-python/2.7/idlelib/idle.bat b/lib-python/2.7/idlelib/idle.bat --- a/lib-python/2.7/idlelib/idle.bat +++ b/lib-python/2.7/idlelib/idle.bat @@ -1,4 +1,4 @@ - at echo off -rem Start IDLE using the appropriate Python interpreter -set CURRDIR=%~dp0 -start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 + at echo off +rem Start IDLE using the appropriate Python interpreter +set CURRDIR=%~dp0 +start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/lib-python/2.7/idlelib/idle_test/test_calltips.py b/lib-python/2.7/idlelib/idle_test/test_calltips.py --- a/lib-python/2.7/idlelib/idle_test/test_calltips.py +++ b/lib-python/2.7/idlelib/idle_test/test_calltips.py @@ -55,7 +55,8 @@ def gtest(obj, out): self.assertEqual(signature(obj), out) - gtest(List, '()\n' + List.__doc__) + if List.__doc__ is not None: + gtest(List, '()\n' + List.__doc__) gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') gtest(list.__init__, @@ -70,7 +71,8 @@ def test_signature_wrap(self): # This is also a test of an old-style class - self.assertEqual(signature(textwrap.TextWrapper), '''\ + if textwrap.TextWrapper.__doc__ is not None: + self.assertEqual(signature(textwrap.TextWrapper), '''\ (width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True)''') @@ -106,20 +108,23 @@ def t5(a, b=None, *args, **kwds): 'doc' t5.tip = "(a, b=None, *args, **kwargs)" + doc = '\ndoc' if t1.__doc__ is not None else '' for func in (t1, t2, t3, t4, t5, TC): - self.assertEqual(signature(func), func.tip + '\ndoc') + self.assertEqual(signature(func), func.tip + doc) def test_methods(self): + doc = '\ndoc' if TC.__doc__ is not None else '' for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): - self.assertEqual(signature(meth), meth.tip + "\ndoc") - self.assertEqual(signature(TC.cm), "(a)\ndoc") - self.assertEqual(signature(TC.sm), "(b)\ndoc") + self.assertEqual(signature(meth), meth.tip + doc) + self.assertEqual(signature(TC.cm), "(a)" + doc) + self.assertEqual(signature(TC.sm), "(b)" + doc) def test_bound_methods(self): # test that first parameter is correctly removed from argspec + doc = '\ndoc' if TC.__doc__ is not None else '' for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): - self.assertEqual(signature(meth), mtip + "\ndoc") + self.assertEqual(signature(meth), mtip + doc) def test_starred_parameter(self): # test that starred first parameter is *not* removed from argspec diff --git a/lib-python/2.7/idlelib/idle_test/test_io.py b/lib-python/2.7/idlelib/idle_test/test_io.py new file mode 100644 --- /dev/null +++ b/lib-python/2.7/idlelib/idle_test/test_io.py @@ -0,0 +1,267 @@ +import unittest +import io +from idlelib.PyShell import PseudoInputFile, PseudoOutputFile +from test import test_support as support + + +class Base(object): + def __str__(self): + return '%s:str' % type(self).__name__ + def __unicode__(self): + return '%s:unicode' % type(self).__name__ + def __len__(self): + return 3 + def __iter__(self): + return iter('abc') + def __getitem__(self, *args): + return '%s:item' % type(self).__name__ + def __getslice__(self, *args): + return '%s:slice' % type(self).__name__ + +class S(Base, str): + pass + +class U(Base, unicode): + pass + +class BA(Base, bytearray): + pass + +class MockShell: + def __init__(self): + self.reset() + + def write(self, *args): + self.written.append(args) + + def readline(self): + return self.lines.pop() + + def close(self): + pass + + def reset(self): + self.written = [] + + def push(self, lines): + self.lines = list(lines)[::-1] + + +class PseudeOutputFilesTest(unittest.TestCase): + def test_misc(self): + shell = MockShell() + f = PseudoOutputFile(shell, 'stdout', 'utf-8') + self.assertIsInstance(f, io.TextIOBase) + self.assertEqual(f.encoding, 'utf-8') + self.assertIsNone(f.errors) + self.assertIsNone(f.newlines) + self.assertEqual(f.name, '') + self.assertFalse(f.closed) + self.assertTrue(f.isatty()) + self.assertFalse(f.readable()) + self.assertTrue(f.writable()) + self.assertFalse(f.seekable()) + + def test_unsupported(self): + shell = MockShell() + f = PseudoOutputFile(shell, 'stdout', 'utf-8') + self.assertRaises(IOError, f.fileno) + self.assertRaises(IOError, f.tell) + self.assertRaises(IOError, f.seek, 0) + self.assertRaises(IOError, f.read, 0) + self.assertRaises(IOError, f.readline, 0) + + def test_write(self): + shell = MockShell() + f = PseudoOutputFile(shell, 'stdout', 'utf-8') + f.write('test') + self.assertEqual(shell.written, [('test', 'stdout')]) + shell.reset() + f.write('t\xe8st') + self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) + shell.reset() + f.write(u't\xe8st') + self.assertEqual(shell.written, [(u't\xe8st', 'stdout')]) + shell.reset() + + f.write(S('t\xe8st')) + self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), str) + shell.reset() + f.write(BA('t\xe8st')) + self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), str) + shell.reset() + f.write(U(u't\xe8st')) + self.assertEqual(shell.written, [(u't\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), unicode) + shell.reset() + + self.assertRaises(TypeError, f.write) + self.assertEqual(shell.written, []) + self.assertRaises(TypeError, f.write, 123) + self.assertEqual(shell.written, []) + self.assertRaises(TypeError, f.write, 'test', 'spam') + self.assertEqual(shell.written, []) + + def test_writelines(self): + shell = MockShell() + f = PseudoOutputFile(shell, 'stdout', 'utf-8') + f.writelines([]) + self.assertEqual(shell.written, []) + shell.reset() + f.writelines(['one\n', 'two']) + self.assertEqual(shell.written, + [('one\n', 'stdout'), ('two', 'stdout')]) + shell.reset() + f.writelines(['on\xe8\n', 'tw\xf2']) + self.assertEqual(shell.written, + [('on\xe8\n', 'stdout'), ('tw\xf2', 'stdout')]) + shell.reset() + f.writelines([u'on\xe8\n', u'tw\xf2']) + self.assertEqual(shell.written, + [(u'on\xe8\n', 'stdout'), (u'tw\xf2', 'stdout')]) + shell.reset() + + f.writelines([S('t\xe8st')]) + self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), str) + shell.reset() + f.writelines([BA('t\xe8st')]) + self.assertEqual(shell.written, [('t\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), str) + shell.reset() + f.writelines([U(u't\xe8st')]) + self.assertEqual(shell.written, [(u't\xe8st', 'stdout')]) + self.assertEqual(type(shell.written[0][0]), unicode) + shell.reset() + + self.assertRaises(TypeError, f.writelines) + self.assertEqual(shell.written, []) + self.assertRaises(TypeError, f.writelines, 123) + self.assertEqual(shell.written, []) + self.assertRaises(TypeError, f.writelines, [123]) + self.assertEqual(shell.written, []) + self.assertRaises(TypeError, f.writelines, [], []) + self.assertEqual(shell.written, []) + + def test_close(self): + shell = MockShell() + f = PseudoOutputFile(shell, 'stdout', 'utf-8') + self.assertFalse(f.closed) + f.write('test') + f.close() + self.assertTrue(f.closed) + self.assertRaises(ValueError, f.write, 'x') + self.assertEqual(shell.written, [('test', 'stdout')]) + f.close() + self.assertRaises(TypeError, f.close, 1) + + +class PseudeInputFilesTest(unittest.TestCase): + def test_misc(self): + shell = MockShell() + f = PseudoInputFile(shell, 'stdin', 'utf-8') + self.assertIsInstance(f, io.TextIOBase) + self.assertEqual(f.encoding, 'utf-8') + self.assertIsNone(f.errors) + self.assertIsNone(f.newlines) + self.assertEqual(f.name, '') + self.assertFalse(f.closed) + self.assertTrue(f.isatty()) + self.assertTrue(f.readable()) + self.assertFalse(f.writable()) + self.assertFalse(f.seekable()) + + def test_unsupported(self): + shell = MockShell() + f = PseudoInputFile(shell, 'stdin', 'utf-8') + self.assertRaises(IOError, f.fileno) + self.assertRaises(IOError, f.tell) + self.assertRaises(IOError, f.seek, 0) + self.assertRaises(IOError, f.write, 'x') + self.assertRaises(IOError, f.writelines, ['x']) + From noreply at buildbot.pypy.org Tue Sep 15 14:48:49 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 15 Sep 2015 14:48:49 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: fix merge with renamed llop/resop Message-ID: <20150915124849.214A91C03CF@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79646:322e4fe034c6 Date: 2015-09-15 14:48 +0200 http://bitbucket.org/pypy/pypy/changeset/322e4fe034c6/ Log: fix merge with renamed llop/resop diff --git a/rpython/jit/backend/llsupport/stmrewrite.py b/rpython/jit/backend/llsupport/stmrewrite.py --- a/rpython/jit/backend/llsupport/stmrewrite.py +++ b/rpython/jit/backend/llsupport/stmrewrite.py @@ -88,7 +88,7 @@ rop.ENTER_PORTAL_FRAME, rop.LEAVE_PORTAL_FRAME, rop.MARK_OPAQUE_PTR, rop.JIT_DEBUG, rop.KEEPALIVE, - rop.QUASIIMMUT_FIELD, rop.RECORD_KNOWN_CLASS, + rop.QUASIIMMUT_FIELD, rop.RECORD_EXACT_CLASS, ): self.newop(op) return diff --git a/rpython/translator/stm/inevitable.py b/rpython/translator/stm/inevitable.py --- a/rpython/translator/stm/inevitable.py +++ b/rpython/translator/stm/inevitable.py @@ -19,7 +19,7 @@ 'stack_current', 'gc_stack_bottom', 'cast_ptr_to_int', 'jit_force_virtual', 'jit_force_virtualizable', 'jit_force_quasi_immutable', 'jit_marker', 'jit_is_virtual', - 'jit_record_known_class', 'jit_ffi_save_result', + 'jit_record_exact_class', 'jit_ffi_save_result', 'gc_identityhash', 'gc_id', 'gc_can_move', 'gc__collect', 'gc_adr_of_root_stack_top', 'gc_add_memory_pressure', 'gc_pin', 'gc_unpin', 'gc__is_pinned', From noreply at buildbot.pypy.org Tue Sep 15 14:48:51 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Tue, 15 Sep 2015 14:48:51 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: import stmgc Message-ID: <20150915124851.543A31C03CF@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79647:808c350438ad Date: 2015-09-15 14:48 +0200 http://bitbucket.org/pypy/pypy/changeset/808c350438ad/ Log: import stmgc diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -8cba33de2246+ +7d754bc0f3a7 diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c --- a/rpython/translator/stm/src_stm/stm/core.c +++ b/rpython/translator/stm/src_stm/stm/core.c @@ -1212,8 +1212,6 @@ in abort_data_structures_from_segment_num() */ STM_SEGMENT->nursery_mark = ((stm_char *)_stm_nursery_start + stm_fill_mark_nursery_bytes); - } else if (repeat_count >= 5) { - _stm_become_inevitable("too many retries"); } return repeat_count; } diff --git a/rpython/translator/stm/src_stm/stm/hashtable.c b/rpython/translator/stm/src_stm/stm/hashtable.c --- a/rpython/translator/stm/src_stm/stm/hashtable.c +++ b/rpython/translator/stm/src_stm/stm/hashtable.c @@ -180,6 +180,8 @@ char *to_read_from = segment_base; if (segnum != -1) { /* -> compaction during major GC */ + /* it's possible that we just created this entry, and it wasn't + touched in this segment yet. Then seg0 is up-to-date. */ to_read_from = get_page_status_in(segnum, (uintptr_t)entry / 4096UL) == PAGE_NO_ACCESS ? stm_object_pages : to_read_from; if (((struct stm_hashtable_entry_s *) @@ -359,7 +361,7 @@ uintptr_t key) { stm_hashtable_entry_t *e = stm_hashtable_lookup(hobj, hashtable, key); - stm_read((object_t *)e); + // stm_read((object_t *)e); - done in _lookup() return e->object; } diff --git a/rpython/translator/stm/src_stm/stm/nursery.c b/rpython/translator/stm/src_stm/stm/nursery.c --- a/rpython/translator/stm/src_stm/stm/nursery.c +++ b/rpython/translator/stm/src_stm/stm/nursery.c @@ -778,8 +778,16 @@ char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj); size_t size = stmcb_size_rounded_up((struct object_s *)realobj); - /* always gets outside as a large object for now (XXX?) */ - object_t *nobj = (object_t *)allocate_outside_nursery_large(size); + /* always gets outside */ + object_t *nobj; + if (size > GC_LAST_SMALL_SIZE) { + /* case 1: object is not small enough. + Ask gcpage.c for an allocation via largemalloc. */ + nobj = (object_t *)allocate_outside_nursery_large(size); + } else { + /* case "small enough" */ + nobj = (object_t *)allocate_outside_nursery_small(size); + } /* Initialize the shadow enough to be considered a valid gc object. If the original object stays alive at the next minor collection, From noreply at buildbot.pypy.org Tue Sep 15 16:55:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 15 Sep 2015 16:55:51 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: Backed out changeset c06257c68c32 - does not seem to help Message-ID: <20150915145551.B8FCF1C10FF@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79648:bd8081e25404 Date: 2015-09-15 16:55 +0200 http://bitbucket.org/pypy/pypy/changeset/bd8081e25404/ Log: Backed out changeset c06257c68c32 - does not seem to help 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 @@ -573,15 +573,13 @@ return else: guard_op = self.replace_op_with(op, op.getopnum()) - if self._last_guard_op and self._last_guard_count < 5: + if self._last_guard_op: op = self._copy_resume_data_from(guard_op, self._last_guard_op) - self._last_guard_count += 1 else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) self._last_guard_op = op - self._last_guard_count = 0 # for unrolling for farg in op.getfailargs(): if farg: From noreply at buildbot.pypy.org Tue Sep 15 17:16:56 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 15 Sep 2015 17:16:56 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: fighting with casting. not quite there, but soon scheduling tests should work Message-ID: <20150915151656.F3FBF1C10FF@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79649:9d05ed8b7873 Date: 2015-09-15 17:17 +0200 http://bitbucket.org/pypy/pypy/changeset/9d05ed8b7873/ Log: fighting with casting. not quite there, but soon scheduling tests should work diff --git a/rpython/jit/metainterp/optimizeopt/renamer.py b/rpython/jit/metainterp/optimizeopt/renamer.py --- a/rpython/jit/metainterp/optimizeopt/renamer.py +++ b/rpython/jit/metainterp/optimizeopt/renamer.py @@ -1,3 +1,5 @@ +from rpython.jit.metainterp import resoperation +from rpython.jit.metainterp.resume import Snapshot class Renamer(object): def __init__(self): diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -15,11 +15,20 @@ self.graph = graph self.oplist = [] self.worklist = [] + self.invariant_oplist = [] + self.invariant_vector_vars = [] def post_schedule(self): loop = self.graph.loop self.renamer.rename(loop.jump) loop.operations = self.oplist + loop.prefix = self.invariant_oplist + if len(self.invariant_vector_vars) > 0: + # TODO, accum? + args = loop.label.getarglist_copy() + self.invariant_vector_vars + opnum = loop.label.getopnum() + # TODO descr? + loop.prefix_label = loop.label.copy_and_change(opnum, args) def profitable(self): return self.costmodel.profitable() @@ -67,7 +76,7 @@ Keeps worklist sorted (see priority) """ op = node.getoperation() state.renamer.rename(op) - state.unpack_from_vector(op) + state.ensure_args_unpacked(op) node.position = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY @@ -105,6 +114,7 @@ if not node.emitted: op = node.getoperation() self.mark_emitted(node, state) + state.seen[op] = None state.oplist.append(op) continue @@ -120,52 +130,6 @@ for node in state.graph.nodes: assert node.emitted -def vectorbox_outof_box(box, count=-1, size=-1, type='-'): - if box.type not in (FLOAT, INT): - raise AssertionError("cannot create vector box of type %s" % (box.type)) - signed = True - if box.type == FLOAT: - signed = False - return BoxVector(box.type, 2, 8, signed) - -def packtype_outof_box(box): - if box.type == VECTOR: - return Type.of(box) - else: - if box.type == INT: - return Type(INT, 8, True, 2) - elif box.type == FLOAT: - return Type(FLOAT, 8, False, 2) - # - raise AssertionError("box %s not supported" % (box,)) - -def vectorbox_clone_set(box, count=-1, size=-1, type='-', clone_signed=True, signed=False): - if count == -1: - count = box.getcount() - if size == -1: - size = box.getsize() - if type == '-': - type = box.gettype() - if clone_signed: - signed = box.getsigned() - return BoxVector(type, count, size, signed) - -def getpackopnum(type): - if type == INT: - return rop.VEC_INT_PACK - elif type == FLOAT: - return rop.VEC_FLOAT_PACK - # - raise AssertionError("getpackopnum type %s not supported" % (type,)) - -def getunpackopnum(type): - if type == INT: - return rop.VEC_INT_UNPACK - elif type == FLOAT: - return rop.VEC_FLOAT_UNPACK - # - raise AssertionError("getunpackopnum type %s not supported" % (type,)) - #UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, # rop.UINT_LT, rop.UINT_LE, # rop.UINT_GT, rop.UINT_GE) @@ -275,27 +239,6 @@ def bytecount(self): return self.count * self.type.bytecount() -class DataTyper(object): - - def infer_type(self, op): - # default action, pass through: find the first arg - # the output is the same as the first argument! - if op.returns_void() or op.argcount() == 0: - return - arg0 = op.getarg(0) - op.setdatatype(arg0.datatype, arg0.bytesize, arg0.signed) - -class PassFirstArg(TypeOutput): - def __init__(self): - pass - -def update_arg_in_vector_pos(state, argidx, box): - arguments = [op.getoperation().getarg(argidx) for op in self.getoperations()] - for i,arg in enumerate(arguments): - #if i >= box.count: - # break - state.setvector_of_box(arg, i, box) - class TypeRestrict(object): ANY_TYPE = -1 ANY_SIZE = -1 @@ -320,7 +263,6 @@ return True class trans(object): - #DT_PASS = DataTyper() TR_ANY = TypeRestrict() TR_ANY_FLOAT = TypeRestrict(FLOAT) @@ -355,16 +297,9 @@ rop.VEC_FLOAT_ABS: [TR_ANY_FLOAT], rop.VEC_FLOAT_NEG: [TR_ANY_FLOAT], - rop.VEC_RAW_LOAD_I: [None, None, TR_ANY], - rop.VEC_RAW_LOAD_F: [None, None, TR_ANY], - rop.VEC_GETARRAYITEM_RAW_I: [None, None, TR_ANY], - rop.VEC_GETARRAYITEM_RAW_F: [None, None, TR_ANY], - rop.VEC_GETARRAYITEM_GC_I: [None, None, TR_ANY], - rop.VEC_GETARRAYITEM_GC_F: [None, None, TR_ANY], - - rop.VEC_RAW_STORE: [None, None, None, TR_ANY], - rop.VEC_SETARRAYITEM_RAW: [None, None, None, TR_ANY], - rop.VEC_SETARRAYITEM_GC: [None, None, None, TR_ANY], + rop.VEC_RAW_STORE: [None, None, TR_ANY], + rop.VEC_SETARRAYITEM_RAW: [None, None, TR_ANY], + rop.VEC_SETARRAYITEM_GC: [None, None, TR_ANY], rop.GUARD_TRUE: [TR_ANY_INTEGER], rop.GUARD_FALSE: [TR_ANY_INTEGER], @@ -427,12 +362,13 @@ # a) expand vars/consts before the label and add as argument # b) expand vars created in the loop body # - restrictions = trans.MAPPING[pack.leftmost().vector] + restrictions = trans.MAPPING.get(pack.leftmost().vector, []) + if not restrictions: + return for i,arg in enumerate(args): if i >= len(restrictions) or restrictions[i] is None: # ignore this argument continue - print "trans", i, "arg", arg if arg.returns_vector(): continue pos, vecop = state.getvector_of_box(arg) @@ -442,40 +378,32 @@ continue args[i] = vecop assemble_scattered_values(state, pack, args, i) - position_values(state, pack, args, i, arg, pos) + position_values(state, pack, args, i, pos) def assemble_scattered_values(state, pack, args, index): vectors = pack.argument_vectors(state, pack, index) if len(vectors) > 1: # the argument is scattered along different vector boxes - value = gather(vectors, packable) - update_arg_in_vector_pos(state, i, value) - args[i] = value - #if packed < packable and len(vboxes) > 1: - # # the argument is scattered along different vector boxes - # args[i] = self.gather(vboxes, packable) - # self.update_arg_in_vector_pos(i, args[i]) - # continue + args[index] = gather(state, vectors, pack.numops()) + state.remember_args_in_vector(pack, index, args[index]) -def gather(self, vboxes, target_count): # packed < packable and packed < stride: - (_, box) = vboxes[0] +def gather(state, vectors, count): # packed < packable and packed < stride: + (_, arg) = vectors[0] i = 1 - while i < len(vboxes): - (box2_pos, box2) = vboxes[i] - if box.getcount() + box2.getcount() <= target_count: - box = self.package(box, box.getcount(), - box2, box2_pos, box2.getcount()) + while i < len(vectors): + (newarg_pos, newarg) = vectors[i] + if arg.count + newarg.count <= count: + arg = pack_into_vector(state, arg, arg.count, newarg, newarg_pos, newarg.count) i += 1 - return box + return arg -def position_values(state, pack, args, index, arg, pos): - pass - #if pos != 0: - # # The vector box is at a position != 0 but it - # # is required to be at position 0. Unpack it! - # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) - # self.update_arg_in_vector_pos(i, args[i]) - # continue +def position_values(state, pack, args, index, position): + if position != 0: + # The vector box is at a position != 0 but it + # is required to be at position 0. Unpack it! + arg = args[index] + args[index] = unpack_from_vector(state, arg, position, arg.count - position) + state.remember_args_in_vector(pack, index, args[index]) # convert size i64 -> i32, i32 -> i64, ... # TODO if self.bytesize > 0: @@ -493,7 +421,7 @@ # # pos == 0 then it is already at the right place # if pos != 0: # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) - # self.update_arg_in_vector_pos(i, args[i]) + # state.remember_args_in_vector(i, args[i]) # #self.update_input_output(self.pack) # continue # else: @@ -504,13 +432,13 @@ #if packed < packable and len(vboxes) > 1: # # the argument is scattered along different vector boxes # args[i] = self.gather(vboxes, packable) - # self.update_arg_in_vector_pos(i, args[i]) + # state.remember_args_in_vector(i, args[i]) # continue #if pos != 0: # # The vector box is at a position != 0 but it # # is required to be at position 0. Unpack it! # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) - # self.update_arg_in_vector_pos(i, args[i]) + # state.remember_args_in_vector(i, args[i]) # continue ## #assert vecop is not None @@ -551,53 +479,50 @@ self.vecops.append(op) return vbox_cloned -def unpack(self, vbox, index, count, arg_ptype): +def unpack_from_vector(state, arg, index, count): """ Extract parts of the vector box into another vector box """ - assert index < vbox.getcount() - assert index + count <= vbox.getcount() + print "unpack i", index, "c", count, "v", arg assert count > 0 - vbox_cloned = vectorbox_clone_set(vbox, count=count) - opnum = getunpackopnum(vbox.gettype()) - op = ResOperation(opnum, [vbox, ConstInt(index), ConstInt(count)], vbox_cloned) - self.costmodel.record_vector_unpack(vbox, index, count) - self.vecops.append(op) - # - return vbox_cloned + assert index + count <= arg.count + args = [arg, ConstInt(index), ConstInt(count)] + vecop = OpHelpers.create_vec_unpack(arg.type, args, arg.bytesize, + arg.signed, count) + state.costmodel.record_vector_unpack(arg, index, count) + state.oplist.append(vecop) + return vecop -def package(self, tgt, tidx, src, sidx, scount): +def pack_into_vector(state, tgt, tidx, src, sidx, scount): """ tgt = [1,2,3,4,_,_,_,_] src = [5,6,_,_] new_box = [1,2,3,4,5,6,_,_] after the operation, tidx=4, scount=2 """ assert sidx == 0 # restriction - count = tgt.getcount() + src.getcount() - new_box = vectorbox_clone_set(tgt, count=count) - opnum = getpackopnum(tgt.gettype()) - op = ResOperation(opnum, [tgt, src, ConstInt(tidx), ConstInt(scount)], new_box) - self.vecops.append(op) - self.costmodel.record_vector_pack(src, sidx, scount) + newcount = tgt.count + scount + args = [tgt, src, ConstInt(tidx), ConstInt(scount)] + vecop = OpHelpers.create_vec_pack(tgt.type, args, tgt.bytesize, tgt.signed, newcount) + state.oplist.append(vecop) + state.costmodel.record_vector_pack(src, sidx, scount) if not we_are_translated(): - self._check_vec_pack(op) - return new_box + _check_vec_pack(vecop) + return vecop -def _check_vec_pack(self, op): - result = op +def _check_vec_pack(op): arg0 = op.getarg(0) arg1 = op.getarg(1) index = op.getarg(2) count = op.getarg(3) - assert isinstance(result, BoxVector) - assert isinstance(arg0, BoxVector) - assert isinstance(index, ConstInt) + assert op.is_vector() + assert arg0.is_vector() + assert index.is_constant() assert isinstance(count, ConstInt) - assert arg0.getsize() == result.getsize() - if isinstance(arg1, BoxVector): - assert arg1.getsize() == result.getsize() + assert arg0.bytesize == op.bytesize + if arg1.is_vector(): + assert arg1.bytesize == op.bytesize else: assert count.value == 1 - assert index.value < result.getcount() - assert index.value + count.value <= result.getcount() - assert result.getcount() > arg0.getcount() + assert index.value < op.count + assert index.value + count.value <= op.count + assert op.count > arg0.count def expand(state, pack, args, arg, index): """ Expand a value into a vector box. useful for arith metic @@ -610,7 +535,8 @@ ops = state.invariant_oplist variables = state.invariant_vector_vars if not arg.is_constant() and arg not in state.inputargs: - ops = self.vecops + # cannot be created before the loop, expand inline + ops = state.oplist variables = None for i, node in enumerate(pack.operations): @@ -620,29 +546,30 @@ i += 1 else: # note that heterogenous nodes are not yet tracked - already_expanded = expanded_map.get(arg, None) - if already_expanded: - return already_expanded + vecop = expanded_map.get(arg, None) + if vecop: + args[index] = vecop + return vecop vecop = OpHelpers.create_vec_expand(arg, op.bytesize, op.signed, pack.numops()) - state.oplist.append(vecop) + ops.append(vecop) if variables is not None: variables.append(vecop) expanded_map[arg] = vecop - for i in range(vecop.count): - state.setvector_of_box(arg, i, vecop) + #for i in range(vecop.count): + # state.setvector_of_box(arg, i, vecop) args[index] = vecop return vecop vecop = OpHelpers.create_vec(arg.type, left.bytesize, left.signed) - state.oplist.append(vecop) + ops.append(vecop) for i,node in enumerate(pack.operations): op = node.getoperation() arg = op.getarg(index) arguments = [vecop, arg, ConstInt(i), ConstInt(1)] vecop = OpHelpers.create_vec_pack(arg.type, arguments, left.bytesize, left.signed, vecop.count+1) - state.setvector_of_box(arg, i, vecop) - state.oplist.append(vecop) + #state.setvector_of_box(arg, i, vecop) + ops.append(vecop) if variables is not None: variables.append(vecop) @@ -654,8 +581,6 @@ self.box_to_vbox = {} self.cpu = cpu self.vec_reg_size = cpu.vector_register_size - self.invariant_oplist = [] - self.invariant_vector_vars = [] self.expanded_map = {} self.costmodel = costmodel self.inputargs = {} @@ -666,7 +591,7 @@ def post_schedule(self): loop = self.graph.loop - self.unpack_from_vector(loop.jump) + self.ensure_args_unpacked(loop.jump) SchedulerState.post_schedule(self) # add accumulation info to the descriptor @@ -727,47 +652,41 @@ return True return False - def unpack_from_vector(self, op): + def ensure_args_unpacked(self, op): """ If a box is needed that is currently stored within a vector box, this utility creates a unpacking instruction. """ - args = op.getarglist() - # unpack for an immediate use - for i, arg in enumerate(op.getarglist()): - if not arg.is_constant(): - argument = self._unpack_from_vector(i, arg) - if arg is not argument: - op.setarg(i, argument) - if not op.returns_void(): - self.seen[op] = None + for i, argument in enumerate(op.getarglist()): + if not argument.is_constant(): + arg = self.ensure_unpacked(i, argument) + if argument is not arg: + op.setarg(i, arg) # unpack for a guard exit if op.is_guard(): + # could be moved to the guard exit fail_args = op.getfailargs() - for i, arg in enumerate(fail_args): - if arg and not arg.is_constant(): - argument = self._unpack_from_vector(i, arg) - if arg is not argument: - fail_args[i] = argument + for i, argument in enumerate(fail_args): + if argument and not argument.is_constant(): + arg = self.ensure_unpacked(i, argument) + if argument is not arg: + fail_arguments[i] = arg - def _unpack_from_vector(self, i, arg): - if arg in self.seen or arg.type == 'V': + def ensure_unpacked(self, index, arg): + if arg in self.seen or not arg.is_vector(): return arg - (j, vbox) = self.getvector_of_box(arg) - if vbox: - if vbox in self.invariant_vector_vars: + (pos, var) = self.getvector_of_box(arg) + if var: + if var in self.invariant_vector_vars: return arg - arg_cloned = arg.clonebox() - self.seen[arg_cloned] = None - self.renamer.start_renaming(arg, arg_cloned) - self.setvector_of_box(arg_cloned, j, vbox) - cj = ConstInt(j) - ci = ConstInt(1) - opnum = getunpackopnum(vbox.gettype()) - unpack_op = ResOperation(opnum, [vbox, cj, ci], arg_cloned) - self.costmodel.record_vector_unpack(vbox, j, 1) - self.oplist.append(unpack_op) - return arg_cloned + args = [var, ConstInt(pos), ConstInt(1)] + vecop = OpHelpers.create_vec_unpack(var.type, args, var.bytesize, + var.signed, 1) + self.renamer.start_renaming(arg, vecop) + self.seen[vecop] = None + self.costmodel.record_vector_unpack(var, pos, 1) + self.oplist.append(vecop) + return vecop return arg def _prevent_signext(self, outsize, insize): @@ -783,11 +702,24 @@ assert not var.is_vector() self.box_to_vbox[var] = (off, vector) + def remember_args_in_vector(self, pack, index, box): + arguments = [op.getoperation().getarg(index) for op in pack.operations] + for i,arg in enumerate(arguments): + if i >= box.count: + break + self.setvector_of_box(arg, i, box) + + def opcount_filling_vector_register(pack, vec_reg_size): """ how many operations of that kind can one execute with a machine instruction of register size X? """ op = pack.leftmost() + if op.returns_void(): + assert op.is_primitive_store() + arg = op.getarg(2) + return vec_reg_size // arg.bytesize + if op.is_typecast(): if op.casts_down(): return vec_reg_size // op.cast_from_bytesize() @@ -806,13 +738,6 @@ self.operations = ops self.accum = None self.update_pack_of_nodes() - # initializes the type - # TODO - #input_type, output_type = \ - # determine_input_output_types(origin_pack, lnode, forward) - #self.input_type = input_type - #self.output_type = output_type - #assert self.input_type is not None or self.output_type is not None def numops(self): return len(self.operations) @@ -853,6 +778,11 @@ """ left = self.leftmost() if left.returns_void(): + if left.is_primitive_store(): + # make this case more general if it turns out this is + # not the only case where packs need to be trashed + indexarg = left.getarg(2) + return indexarg.bytesize * self.numops() - vec_reg_size return 0 if self.numops() == 0: return -1 @@ -860,7 +790,9 @@ # casting is special, often only takes a half full vector if left.casts_down(): # size is reduced - return left.cast_from_bytesize() * self.numops() - vec_reg_size + size = left.cast_input_bytesize(vec_reg_size) + import pdb; pdb.set_trace() + return left.cast_from_bytesize() * self.numops() - size else: # size is increased return left.cast_to_bytesize() * self.numops() - vec_reg_size @@ -897,7 +829,8 @@ oplist, newoplist = pack.slice_operations(vec_reg_size) pack.operations = oplist pack.update_pack_of_nodes() - assert pack.is_full(vec_reg_size) + if not pack.leftmost().is_typecast(): + assert pack.is_full(vec_reg_size) # newpack = pack.clone(newoplist) load = newpack.pack_load(vec_reg_size) @@ -1195,7 +1128,7 @@ # # box_pos == 0 then it is already at the right place # if box_pos != 0: # args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# self.update_arg_in_vector_pos(i, args[i]) +# remember_args_in_vector(i, args[i]) # #self.update_input_output(self.pack) # continue # else: @@ -1206,13 +1139,13 @@ # if packed < packable and len(vboxes) > 1: # # the argument is scattered along different vector boxes # args[i] = self.gather(vboxes, packable) -# self.update_arg_in_vector_pos(i, args[i]) +# remember_args_in_vector(i, args[i]) # continue # if box_pos != 0: # # The vector box is at a position != 0 but it # # is required to be at position 0. Unpack it! # args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# self.update_arg_in_vector_pos(i, args[i]) +# remember_args_in_vector(i, args[i]) # continue # #self.update_input_output(self.pack) # # diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -82,13 +82,14 @@ jitdriver_sd = FakeJitDriverStaticData() opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, 0) opt.packset = packset - if not prepend_invariant: - state.prepend_invariant_operations = lambda list, _: list opt.combine_packset() opt.schedule(state) # works for now. might be the wrong class? # wrap label + operations + jump it in tree loop otherwise - return state.graph.loop + loop = state.graph.loop + if prepend_invariant: + loop.operations = loop.prefix + loop.operations + return loop class Test(SchedulerBaseTest, LLtypeMixin): @@ -358,13 +359,12 @@ """, False) self.assert_equal(loop2, loop3) - def test_split_load_store(self): loop1 = self.parse_trace(""" - i10 = raw_load_f(p0, i1, descr=float) - i11 = raw_load_f(p0, i2, descr=float) - i12 = raw_load_f(p0, i3, descr=float) - i13 = raw_load_f(p0, i4, descr=float) + i10 = raw_load_i(p0, i1, descr=float) + i11 = raw_load_i(p0, i2, descr=float) + i12 = raw_load_i(p0, i3, descr=float) + i13 = raw_load_i(p0, i4, descr=float) raw_store(p0, i3, i10, descr=float) raw_store(p0, i4, i11, descr=float) """) @@ -454,11 +454,12 @@ def test_combine_packset_nearly_empty_pack(self): trace = self.parse_trace(""" - i10 = int_add(i1, i3) - i11 = int_add(i2, i3) + i10 = int_add(i1, i1) + i11 = int_add(i2, i2) + i12 = int_add(i3, i3) """) pack = self.pack(trace, 0, 2) packset = FakePackSet([pack]) packset.split_overloaded_packs() - assert len(packset.packs) == 0 + assert len(packset.packs) == 1 diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -21,8 +21,7 @@ MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, - Scheduler, Pack, Pair, AccumPair, vectorbox_outof_box, getpackopnum, - getunpackopnum) + Scheduler, Pack, Pair, AccumPair) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) from rpython.rlib import listsort @@ -45,6 +44,11 @@ def operation_list(self): return [self.label] + self.operations + [self.jump] + def assemble_oplist(self): + oplist = self.prefix + [self.prefix_label] + \ + loop.operations + [loop.jump] + return oplist + def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ user_code = not jitdriver_sd.vec and warmstate.vec_all @@ -75,7 +79,7 @@ (opt.unroll_count+1, len(version.operations), len(loop.operations), nano)) debug_stop("vec-opt-loop") # - return info, loop.operations + [loop.jump] + return info, loop.assemble_oplist() except NotAVectorizeableLoop: debug_stop("vec-opt-loop") # vectorization is not possible @@ -625,7 +629,7 @@ self.savings += -count def record_vector_pack(self, src, index, count): - if src.gettype() == FLOAT: + if src.datatype == FLOAT: if index == 1 and count == 1: self.savings -= 2 return @@ -826,6 +830,7 @@ def split_overloaded_packs(self): newpacks = [] + import pdb; pdb.set_trace() for i,pack in enumerate(self.packs): load = pack.pack_load(self.vec_reg_size) if load > Pack.FULL: diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -92,7 +92,13 @@ return op def VecOperation(opnum, args, baseop, count, descr=None): - return VecOperationNew(opnum, args, baseop.datatype, baseop.bytesize, baseop.signed, count, descr) + datatype = baseop.datatype + bytesize = baseop.bytesize + if baseop.is_typecast(): + ft,tt = baseop.cast_types() + datatype = tt + bytesize = baseop.cast_to_bytesize() + return VecOperationNew(opnum, args, datatype, bytesize, baseop.signed, count, descr) def VecOperationNew(opnum, args, datateyp, bytesize, signed, count, descr=None): op = ResOperation(opnum, args, descr) @@ -184,7 +190,7 @@ boolreflex = -1 boolinverse = -1 vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement - casts = ('\x00', -1, '\x00', -1) + casts = ('\x00', -1, '\x00', -1, -1) count = -1 def getopnum(self): @@ -271,7 +277,7 @@ memo[self] = num if self.is_vector(): assert isinstance(self, VectorOp) - sres = 'v%d[%dx%s%d] = ' % (num, self.count, self.datatype, self.bytesize * 8) + sres = self.vector_repr(num) + ' = ' else: sres = self.type + str(num) + ' = ' #if self.result is not None: @@ -302,8 +308,7 @@ memo[self] = num if self.is_vector(): assert isinstance(self, VectorOp) - return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, - self.bytesize * 8) + return self.vector_repr(num) return self.type + str(num) def __repr__(self): @@ -451,14 +456,17 @@ def is_typecast(self): return False + def cast_count(self): + return self.casts[4] + def cast_types(self): return self.casts[0], self.casts[2] def cast_to_bytesize(self): - return self.casts[1] + return self.casts[3] def cast_from_bytesize(self): - return self.casts[3] + return self.casts[1] def casts_up(self): return self.cast_to_bytesize() > self.cast_from_bytesize() @@ -657,6 +665,11 @@ return self.bytesize return (type, size) + def cast_input_bytesize(self, vec_reg_size): + count = vec_reg_size // self.cast_to_bytesize() + size = self.cast_from_bytesize() * self.count + return size + class SignExtOp(object): _mixin_ = True @@ -676,11 +689,18 @@ arg = self.getarg(0) return arg.bytesize + def cast_count(self): + return self.casts[4] + + class VectorOp(object): _mixin_ = True - def repr_rpython(self): - return repr_rpython(self, 'bv') + def vector_repr(self, num): + if self.opnum in (rop.VEC_UNPACK_I, rop.VEC_UNPACK_F): + return self.type + str(num) + return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, + self.bytesize * 8) def vector_bytesize(self): assert self.count > 0 @@ -812,7 +832,6 @@ else: raise IndexError - class BinaryOp(object): _mixin_ = True _arg0 = None @@ -1597,3 +1616,13 @@ opnum = rop.VEC_PACK_F return VecOperationNew(opnum, args, datatype, bytesize, signed, count) + @staticmethod + def create_vec_unpack(datatype, args, bytesize, signed, count): + if datatype == 'i': + opnum = rop.VEC_UNPACK_I + else: + assert datatype == 'f' + opnum = rop.VEC_UNPACK_F + return VecOperationNew(opnum, args, datatype, bytesize, signed, count) + + From noreply at buildbot.pypy.org Tue Sep 15 18:50:57 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 15 Sep 2015 18:50:57 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150915165057.B2F511C03CF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r636:464d24cbcbb6 Date: 2015-09-15 18:51 +0200 http://bitbucket.org/pypy/pypy.org/changeset/464d24cbcbb6/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -15,7 +15,7 @@ - $60284 of $105000 (57.4%) + $60308 of $105000 (57.4%)

@@ -23,7 +23,7 @@
  • diff --git a/don4.html b/don4.html --- a/don4.html +++ b/don4.html @@ -9,7 +9,7 @@ @@ -17,7 +17,7 @@ 2nd call: - $29320 of $80000 (36.7%) + $29421 of $80000 (36.8%)
    @@ -25,7 +25,7 @@
  • From noreply at buildbot.pypy.org Wed Sep 16 10:49:34 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 10:49:34 +0200 (CEST) Subject: [pypy-commit] stmgc c8-faster-smallobj-sync: Merge with use-gcc Message-ID: <20150916084934.5D7361C0EFC@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: c8-faster-smallobj-sync Changeset: r1959:7c57425824e9 Date: 2015-09-15 09:52 +0200 http://bitbucket.org/pypy/stmgc/changeset/7c57425824e9/ Log: Merge with use-gcc diff --git a/c8/TODO b/c8/TODO --- a/c8/TODO +++ b/c8/TODO @@ -1,3 +1,10 @@ +- stm_identityhash spends a good time figuring out if an obj is prebuilt + (40% of its time). maybe after setup_prebuilt, we could defer the test + of GCFLAG_HAS_SHADOW in id_or_identityhash to after an address comparison. + I.e., after setup_prebuilt, all objs allocated there could be in some + area at the start of the heap, and can thus be classified by having + an address < some_barrier. (may include some non-prebuilt ones, but + that's ok) (also take care of small prebuilt objs) - fix markers (e.g. become_inevitable doesn't seem to show up) diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c --- a/c8/stm/nursery.c +++ b/c8/stm/nursery.c @@ -794,8 +794,16 @@ char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj); size_t size = stmcb_size_rounded_up((struct object_s *)realobj); - /* always gets outside as a large object for now (XXX?) */ - object_t *nobj = (object_t *)allocate_outside_nursery_large(size); + /* always gets outside */ + object_t *nobj; + if (size > GC_LAST_SMALL_SIZE) { + /* case 1: object is not small enough. + Ask gcpage.c for an allocation via largemalloc. */ + nobj = (object_t *)allocate_outside_nursery_large(size); + } else { + /* case "small enough" */ + nobj = (object_t *)allocate_outside_nursery_small(size); + } /* Initialize the shadow enough to be considered a valid gc object. If the original object stays alive at the next minor collection, From noreply at buildbot.pypy.org Wed Sep 16 10:49:36 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 10:49:36 +0200 (CEST) Subject: [pypy-commit] stmgc use-gcc: implement noconflict objects Message-ID: <20150916084936.7CC471C0EFC@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: use-gcc Changeset: r1960:10e4734e83c7 Date: 2015-09-16 10:49 +0200 http://bitbucket.org/pypy/stmgc/changeset/10e4734e83c7/ Log: implement noconflict objects diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -12,7 +12,7 @@ { assert(undo->type != TYPE_POSITION_MARKER); free(undo->backup); - assert(undo->backup = (char*)-88); + assert(undo->backup = (char*)0xbb); increment_total_allocated(-SLICE_SIZE(undo->slice)); } @@ -308,7 +308,7 @@ } } -static void reset_modified_from_backup_copies(int segment_num); /* forward */ +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj); /* forward */ static bool _stm_validate(void) { @@ -409,6 +409,25 @@ if (LIKELY(!_stm_was_read(obj))) continue; + /* check for NO_CONFLICT flag in seg0. While its data may + not be current there, the flag will be there and is + immutable. (we cannot check in my_segnum bc. we may + only have executed stm_read(o) but not touched its pages + yet -> they may be NO_ACCESS */ + struct object_s *obj0 = (struct object_s *)REAL_ADDRESS(get_segment_base(0), obj); + if (obj0->stm_flags & GCFLAG_NO_CONFLICT) { + /* obj is noconflict and therefore shouldn't cause + an abort. However, from now on, we also assume + that an abort would not roll-back to what is in + the backup copy, as we don't trace the bkcpy + during major GCs. + We choose the approach to reset all our changes + to this obj here, so that we can throw away the + backup copy completely: */ + reset_modified_from_backup_copies(my_segnum, obj); + continue; + } + /* conflict! */ dprintf(("_stm_validate() failed for obj %p\n", obj)); @@ -418,7 +437,7 @@ from the old (but unmodified) version to the newer version. */ - reset_modified_from_backup_copies(my_segnum); + reset_modified_from_backup_copies(my_segnum, NULL); timing_write_read_contention(cl->written, undo); needs_abort = true; break; @@ -1399,7 +1418,7 @@ invoke_general_finalizers(tl); } -static void reset_modified_from_backup_copies(int segment_num) +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj) { #pragma push_macro("STM_PSEGMENT") #pragma push_macro("STM_SEGMENT") @@ -1415,7 +1434,11 @@ for (; undo < end; undo++) { if (undo->type == TYPE_POSITION_MARKER) continue; + object_t *obj = undo->object; + if (only_obj != NULL && obj != only_obj) + continue; + char *dst = REAL_ADDRESS(pseg->pub.segment_base, obj); memcpy(dst + SLICE_OFFSET(undo->slice), @@ -1427,12 +1450,29 @@ SLICE_SIZE(undo->slice), undo->backup)); free_bk(undo); + + if (only_obj != NULL) { + assert(IMPLY(only_obj != NULL, + (((struct object_s *)dst)->stm_flags + & (GCFLAG_NO_CONFLICT + | GCFLAG_WRITE_BARRIER + | GCFLAG_WB_EXECUTED)) + == (GCFLAG_NO_CONFLICT | GCFLAG_WRITE_BARRIER))); + /* copy last element over this one */ + end--; + list->count -= 3; + if (undo < end) + *undo = *end; + undo--; /* next itr */ + } } - /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ - check_all_write_barrier_flags(pseg->pub.segment_base, list); + if (only_obj == NULL) { + /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ + check_all_write_barrier_flags(pseg->pub.segment_base, list); - list_clear(list); + list_clear(list); + } #pragma pop_macro("STM_SEGMENT") #pragma pop_macro("STM_PSEGMENT") } @@ -1468,7 +1508,7 @@ }); acquire_modification_lock_wr(segment_num); - reset_modified_from_backup_copies(segment_num); + reset_modified_from_backup_copies(segment_num, NULL); release_modification_lock_wr(segment_num); _verify_cards_cleared_in_all_lists(pseg); diff --git a/c8/stm/core.h b/c8/stm/core.h --- a/c8/stm/core.h +++ b/c8/stm/core.h @@ -43,6 +43,7 @@ GCFLAG_CARDS_SET = _STM_GCFLAG_CARDS_SET, GCFLAG_VISITED = 0x10, GCFLAG_FINALIZATION_ORDERING = 0x20, + GCFLAG_NO_CONFLICT = _STM_GCFLAG_NO_CONFLICT, /* All remaining bits of the 32-bit 'stm_flags' field are taken by the "overflow number". This is a number that identifies the "overflow objects" from the current transaction among all old @@ -50,7 +51,7 @@ current transaction that have been flushed out of the nursery, which occurs if the same transaction allocates too many objects. */ - GCFLAG_OVERFLOW_NUMBER_bit0 = 0x40 /* must be last */ + GCFLAG_OVERFLOW_NUMBER_bit0 = 0x80 /* must be last */ }; #define SYNC_QUEUE_SIZE 31 diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -162,6 +162,7 @@ #endif #define _STM_GCFLAG_WRITE_BARRIER 0x01 +#define _STM_GCFLAG_NO_CONFLICT 0x40 #define _STM_FAST_ALLOC (66*1024) #define _STM_NSE_SIGNAL_ABORT 1 #define _STM_NSE_SIGNAL_MAX 2 @@ -780,6 +781,24 @@ void stm_queue_tracefn(stm_queue_t *queue, void trace(object_t **)); + +/* stm_allocate_noconflict() allocates a special kind of object. Validation + will never detect conflicts on such an object. However, writes to it can + get lost. More precisely: every possible point for validation during a + transaction may import a committed version of such objs, thereby resetting + it or even contain not-yet-seen values from other (committed) transactions. + Hence, changes to such an obj that a transaction commits may or may not + propagate to other transactions. */ +__attribute__((always_inline)) +static inline object_t *stm_allocate_noconflict(ssize_t size_rounded_up) +{ + object_t *o = stm_allocate(size_rounded_up); + o->stm_flags |= _STM_GCFLAG_NO_CONFLICT; + return o; +} + + + /* ==================== END ==================== */ extern void (*stmcb_expand_marker)(char *segment_base, uintptr_t odd_number, diff --git a/c8/test/support.py b/c8/test/support.py --- a/c8/test/support.py +++ b/c8/test/support.py @@ -45,6 +45,7 @@ object_t *stm_allocate(ssize_t size_rounded_up); object_t *stm_allocate_weakref(ssize_t size_rounded_up); object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up); +object_t *stm_allocate_noconflict(ssize_t size_rounded_up); /*void stm_write_card(); use _checked_stm_write_card() instead */ @@ -664,6 +665,18 @@ lib._set_type_id(o, tid) return o +def stm_allocate_noconflict(size): + o = lib.stm_allocate_noconflict(size) + tid = 42 + size + lib._set_type_id(o, tid) + return o + +def stm_allocate_noconflict_refs(n): + o = lib.stm_allocate_noconflict(HDR + n * WORD) + tid = 421420 + n + lib._set_type_id(o, tid) + return o + def stm_allocate_with_finalizer(size): o = lib.stm_allocate_with_finalizer(size) tid = 42 + size diff --git a/c8/test/test_noconfl.py b/c8/test/test_noconfl.py new file mode 100644 --- /dev/null +++ b/c8/test/test_noconfl.py @@ -0,0 +1,155 @@ +from support import * +import py + + + +class TestNoConflict(BaseTest): + + def test_basic(self): + self.start_transaction() + o = stm_allocate_noconflict(16) + stm_set_char(o, 'x') + self.push_root(o) + self.commit_transaction() + o = self.pop_root() + self.push_root(o) + + self.switch(1) + + self.start_transaction() + assert stm_get_char(o) == 'x' + + def test_propagate_on_validation(self): + self.start_transaction() + o = stm_allocate_noconflict(16) + self.push_root(o) + self.commit_transaction() + + self.start_transaction() + o = self.pop_root() + self.push_root(o) + + self.switch(1) + + self.start_transaction() + assert stm_get_char(o) == '\0' + + self.switch(0) + stm_set_char(o, 'a') + self.commit_transaction() + + self.switch(1, False) + assert stm_get_char(o) == '\0' + stm_validate() + assert stm_get_char(o) == 'a' + + def test_propagate_on_validation2(self): + self.start_transaction() + o = stm_allocate_noconflict(16) + self.push_root(o) + self.commit_transaction() + + self.start_transaction() + o = self.pop_root() + self.push_root(o) + + self.switch(1) + + self.start_transaction() + assert stm_get_char(o) == '\0' + stm_set_char(o, 'b') # later lost + + self.switch(0) + stm_set_char(o, 'a') + self.commit_transaction() + + self.switch(1, False) + assert stm_get_char(o) == 'b' + stm_validate() + assert stm_get_char(o) == 'a' + + def test_abort_doesnt_revert(self): + self.start_transaction() + o = stm_allocate_noconflict(16) + self.push_root(o) + self.commit_transaction() + + self.start_transaction() + o = self.pop_root() + self.push_root(o) + + self.switch(1) + + self.start_transaction() + assert stm_get_char(o) == '\0' + stm_set_char(o, 'b') # later lost + + self.switch(0) + stm_set_char(o, 'a') + self.commit_transaction() + + self.switch(1, False) + assert stm_get_char(o) == 'b' + stm_validate() + assert stm_get_char(o) == 'a' + # now make sure we never revert back to '\0' + # since then we would need to trace backup copies + # in the GC to keep refs alive there + self.abort_transaction() + self.start_transaction() + assert stm_get_char(o) == 'a' + + + def test_huge_obj(self): + self.start_transaction() + o = stm_allocate_noconflict(1000+20*CARD_SIZE) + self.push_root(o) + self.commit_transaction() + self.start_transaction() + o = self.pop_root() + self.push_root(o) + + stm_set_char(o, 'x', HDR, True) + stm_set_char(o, 'y', 1000, True) + + self.switch(1) + self.start_transaction() + assert stm_get_char(o, HDR) == '\0' + stm_set_char(o, 'b', HDR, False) # later lost + + self.switch(0) + self.commit_transaction() + + self.switch(1, False) + assert stm_get_char(o, HDR) == 'b' + assert stm_get_char(o, 1000) == '\0' + stm_validate() + assert stm_get_char(o, HDR) == 'x' + assert stm_get_char(o, 1000) == 'y' + self.abort_transaction() + self.start_transaction() + assert stm_get_char(o, HDR) == 'x' + assert stm_get_char(o, 1000) == 'y' + + def test_only_read(self): + self.start_transaction() + o = stm_allocate_noconflict(16) + self.push_root(o) + self.commit_transaction() + + self.start_transaction() + o = self.pop_root() + self.push_root(o) + + self.switch(1) + + self.start_transaction() + stm_read(o) # don't touch the memory + + self.switch(0) + stm_set_char(o, 'a') + self.commit_transaction() + + self.switch(1, False) + stm_validate() + assert stm_get_char(o) == 'a' diff --git a/c8/test/test_random.py b/c8/test/test_random.py --- a/c8/test/test_random.py +++ b/c8/test/test_random.py @@ -243,6 +243,7 @@ self.root_numbering = 0 self.ref_type_map = {} self.root_sizes = {} + self.noconfl_objs = set() def get_new_root_name(self, is_ref_type, size): self.root_numbering += 1 @@ -261,6 +262,12 @@ self.global_time += 1 return self.global_time + def add_noconfl_obj(self, o): + self.noconfl_objs.add(o) + + def is_noconfl(self, o): + return o in self.noconfl_objs + def push_state_to_other_threads(self, trs): assert not trs.check_must_abort() for ts in self.thread_states: @@ -382,6 +389,27 @@ thread_state.reload_roots(ex) thread_state.register_root(r) +def op_allocate_no_confl(ex, global_state, thread_state): + # copy&paste of op_allocate... + size = global_state.rnd.choice([ + "16", "48", "288", + str(4096+16), + str(80*1024+16), + #"SOME_MEDIUM_SIZE+16", + #"SOME_LARGE_SIZE+16", + ]) + r = global_state.get_new_root_name(False, size) + thread_state.push_roots(ex) + + ex.do('%s = stm_allocate_noconflict(%s)' % (r, size)) + ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r])))) + thread_state.transaction_state.add_root(r, 0, True) + + thread_state.pop_roots(ex) + thread_state.reload_roots(ex) + thread_state.register_root(r) + global_state.add_noconfl_obj(r) + def op_allocate_ref(ex, global_state, thread_state): num = str(global_state.rnd.randrange(1, 1000)) r = global_state.get_new_root_name(True, num) @@ -429,6 +457,10 @@ trs = thread_state.transaction_state is_ref = global_state.has_ref_type(r) try_cards = global_state.rnd.randrange(1, 100) > 5 # and False + # noconfl: + if global_state.is_noconfl(r): + ex.do('stm_write(%s) # noconfl' % r) + return # # decide on a value to write if is_ref: @@ -449,6 +481,10 @@ r = thread_state.get_random_root() trs = thread_state.transaction_state v = trs.read_root(r) + # noconfl: + if global_state.is_noconfl(r): + ex.do('stm_read(%s) # noconfl' % r) + return # offset = global_state.get_root_size(r) + " - 1" if global_state.has_ref_type(r): @@ -576,6 +612,7 @@ [op_write,]*70, [op_allocate,]*10, [op_allocate_ref]*10, + [op_allocate_no_confl]*2, [op_commit_transaction,]*6, [op_abort_transaction,], [op_forget_root]*10, From noreply at buildbot.pypy.org Wed Sep 16 10:49:39 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 10:49:39 +0200 (CEST) Subject: [pypy-commit] stmgc default: make use-gcc the new default Message-ID: <20150916084939.8B6291C0EFC@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: Changeset: r1961:6ca47dad66a6 Date: 2015-09-16 10:50 +0200 http://bitbucket.org/pypy/stmgc/changeset/6ca47dad66a6/ Log: make use-gcc the new default diff too long, truncating to 2000 out of 2714 lines diff --git a/c7/demo/Makefile b/c7/demo/Makefile --- a/c7/demo/Makefile +++ b/c7/demo/Makefile @@ -19,18 +19,20 @@ COMMON = -I.. -pthread -lrt -g -Wall -Werror -DSTM_LARGEMALLOC_TEST +CC = gcc-seg-gs + # note that 'build' is partially optimized but still contains all asserts debug-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DSTM_DEBUGPRINT -DSTM_GC_NURSERY=128 -O0 \ + $(CC) $(COMMON) -DSTM_DEBUGPRINT -DSTM_GC_NURSERY=128 -O0 \ $< -o debug-$* ../stmgc.c build-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DSTM_GC_NURSERY=128 -O1 $< -o build-$* ../stmgc.c + $(CC) $(COMMON) -DSTM_GC_NURSERY=128 -O1 $< -o build-$* ../stmgc.c release-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DNDEBUG -O2 $< -o release-$* ../stmgc.c + $(CC) $(COMMON) -DNDEBUG -O2 $< -o release-$* ../stmgc.c release-htm-%: %.c ../../htm-c7/stmgc.? ../../htm-c7/htm.h - clang $(COMMON) -O2 $< -o release-htm-$* ../../htm-c7/stmgc.c -DUSE_HTM + $(CC) $(COMMON) -O2 $< -o release-htm-$* ../../htm-c7/stmgc.c -DUSE_HTM diff --git a/c7/demo/demo2.c b/c7/demo/demo2.c --- a/c7/demo/demo2.c +++ b/c7/demo/demo2.c @@ -216,7 +216,7 @@ void teardown_list(void) { - STM_POP_ROOT_RET(stm_thread_local); + STM_POP_ROOT_DROP(stm_thread_local); } @@ -256,6 +256,7 @@ stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf); unregister_thread_local(); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } @@ -293,6 +294,7 @@ rewind_jmp_buf rjbuf; status = sem_init(&done, 0, 0); assert(status == 0); + (void)status; stm_setup(); stm_register_thread_local(&stm_thread_local); diff --git a/c7/demo/demo_random.c b/c7/demo/demo_random.c --- a/c7/demo/demo_random.c +++ b/c7/demo/demo_random.c @@ -412,6 +412,7 @@ stm_unregister_thread_local(&stm_thread_local); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } diff --git a/c7/demo/demo_random2.c b/c7/demo/demo_random2.c --- a/c7/demo/demo_random2.c +++ b/c7/demo/demo_random2.c @@ -435,6 +435,7 @@ stm_unregister_thread_local(&stm_thread_local); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } diff --git a/c7/demo/test_shadowstack.c b/c7/demo/test_shadowstack.c --- a/c7/demo/test_shadowstack.c +++ b/c7/demo/test_shadowstack.c @@ -54,7 +54,7 @@ then do a major collection. It should still be found by the tracing logic. */ stm_start_transaction(&stm_thread_local); - STM_POP_ROOT_RET(stm_thread_local); + STM_POP_ROOT_DROP(stm_thread_local); STM_POP_ROOT(stm_thread_local, node); assert(node->value == 129821); STM_PUSH_ROOT(stm_thread_local, NULL); diff --git a/c7/gdb/gdb_stm.py b/c7/gdb/gdb_stm.py --- a/c7/gdb/gdb_stm.py +++ b/c7/gdb/gdb_stm.py @@ -77,34 +77,25 @@ '((struct stm_priv_segment_info_s *)(stm_object_pages+%d))%s' % (get_segment_size() * segment_id + get_psegment_ofs(), field)) -def thread_to_segment_id(thread_id): - base = int_(gdb.parse_and_eval('stm_object_pages')) +def current_segment(): + mytl = int_(gdb.parse_and_eval('&stm_thread_local')) for j in range(1, get_nb_segments() + 1): - #ti = get_psegment(j, '->pub.running_thread->creating_pthread[0]') - ti = get_psegment(j, '->running_pthread') - if int_(ti) == thread_id: + tl = get_psegment(j, '->pub.running_thread') + if int_(tl) == mytl: ts = get_psegment(j, '->transaction_state') if int_(ts) == 0: print >> sys.stderr, "note: transaction_state == 0" return j - raise Exception("thread not found: %r" % (thread_id,)) + raise Exception("no segment seems to be running this thread") def interactive_segment_base(thread=None): if thread is None: - s = gdb.execute('info threads', False, True) - i = s.find('\n* ') - assert i >= 0 - fields = s[i+2:].split() - assert fields[1] == 'Thread' - assert fields[2].startswith('0x') - thread_id = int(fields[2], 16) - segment_id = thread_to_segment_id(thread_id) + segment_id = current_segment() elif thread.type.code == gdb.TYPE_CODE_INT: if 0 <= int_(thread) < 256: segment_id = int_(thread) else: - thread_id = int_(thread) - segment_id = thread_to_segment_id(thread_id) + raise TypeError("segment num not in range") else: raise TypeError("'thread' argument must be an int or not given") return get_segment_base(segment_id) diff --git a/c7/stm/core.c b/c7/stm/core.c --- a/c7/stm/core.c +++ b/c7/stm/core.c @@ -45,7 +45,6 @@ #endif } -__attribute__((always_inline)) static void write_slowpath_overflow_obj(object_t *obj, bool mark_card) { /* An overflow object is an object from the same transaction, but @@ -79,7 +78,6 @@ } } -__attribute__((always_inline)) static void write_slowpath_common(object_t *obj, bool mark_card) { assert(_seems_to_be_running_transaction()); @@ -223,6 +221,7 @@ check_flag_write_barrier(obj); } +__attribute__((flatten)) void _stm_write_slowpath(object_t *obj) { write_slowpath_common(obj, /*mark_card=*/false); @@ -241,6 +240,7 @@ return (size >= _STM_MIN_CARD_OBJ_SIZE); } +__attribute__((flatten)) char _stm_write_slowpath_card_extra(object_t *obj) { /* the PyPy JIT calls this function directly if it finds that an diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c --- a/c7/stm/forksupport.c +++ b/c7/stm/forksupport.c @@ -58,7 +58,7 @@ /* Make a new mmap at some other address, but of the same size as the standard mmap at stm_object_pages */ - int big_copy_fd; + int big_copy_fd = -1; char *big_copy = setup_mmap("stmgc's fork support", &big_copy_fd); /* Copy all the data from the two ranges of objects (large, small) diff --git a/c7/stm/fprintcolor.c b/c7/stm/fprintcolor.c --- a/c7/stm/fprintcolor.c +++ b/c7/stm/fprintcolor.c @@ -1,3 +1,5 @@ +#include + /* ------------------------------------------------------------ */ #ifdef STM_DEBUGPRINT /* ------------------------------------------------------------ */ diff --git a/c7/stmgc.h b/c7/stmgc.h --- a/c7/stmgc.h +++ b/c7/stmgc.h @@ -20,7 +20,15 @@ #endif -#define TLPREFIX __attribute__((address_space(256))) +#ifdef __SEG_GS /* on a custom patched gcc */ +# define TLPREFIX __seg_gs +# define _STM_RM_SUFFIX :8 +#elif defined(__clang__) /* on a clang, hopefully made bug-free */ +# define TLPREFIX __attribute__((address_space(256))) +# define _STM_RM_SUFFIX /* nothing */ +#else +# error "needs either a GCC with __seg_gs support, or a bug-freed clang" +#endif typedef TLPREFIX struct object_s object_t; typedef TLPREFIX struct stm_segment_info_s stm_segment_info_t; @@ -34,11 +42,11 @@ 'STM_SEGMENT->transaction_read_version' if and only if the object was read in the current transaction. The nurseries also have corresponding read markers, but they are never used. */ - uint8_t rm; + unsigned char rm _STM_RM_SUFFIX; }; struct stm_segment_info_s { - uint8_t transaction_read_version; + unsigned int transaction_read_version; int segment_num; char *segment_base; stm_char *nursery_current; @@ -288,6 +296,7 @@ #define STM_PUSH_ROOT(tl, p) ((tl).shadowstack++->ss = (object_t *)(p)) #define STM_POP_ROOT(tl, p) ((p) = (typeof(p))((--(tl).shadowstack)->ss)) #define STM_POP_ROOT_RET(tl) ((--(tl).shadowstack)->ss) +#define STM_POP_ROOT_DROP(tl) ((void)(--(tl).shadowstack)) /* Every thread needs to have a corresponding stm_thread_local_t @@ -302,7 +311,12 @@ /* At some key places, like the entry point of the thread and in the function with the interpreter's dispatch loop, you need to declare - a local variable of type 'rewind_jmp_buf' and call these macros. */ + a local variable of type 'rewind_jmp_buf' and call these macros. + IMPORTANT: a function in which you call stm_rewind_jmp_enterframe() + must never change the value of its own arguments! If they are + passed on the stack, gcc can change the value directly there, but + we're missing the logic to save/restore this part! +*/ #define stm_rewind_jmp_enterprepframe(tl, rjbuf) \ rewind_jmp_enterprepframe(&(tl)->rjthread, rjbuf, (tl)->shadowstack) #define stm_rewind_jmp_enterframe(tl, rjbuf) \ @@ -506,7 +520,7 @@ #define STM_POP_MARKER(tl) ({ \ object_t *_popped = STM_POP_ROOT_RET(tl); \ - STM_POP_ROOT_RET(tl); \ + STM_POP_ROOT_DROP(tl); \ _popped; \ }) diff --git a/c7/test/common.py b/c7/test/common.py --- a/c7/test/common.py +++ b/c7/test/common.py @@ -3,7 +3,7 @@ assert sys.maxint == 9223372036854775807, "requires a 64-bit environment" # ---------- -os.environ['CC'] = 'clang' +os.environ['CC'] = 'gcc-seg-gs' parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/c7/test/support.py b/c7/test/support.py --- a/c7/test/support.py +++ b/c7/test/support.py @@ -478,7 +478,8 @@ ], undef_macros=['NDEBUG'], include_dirs=[parent_dir], - extra_compile_args=['-g', '-O0', '-Werror', '-ferror-limit=1'], + extra_compile_args=['-g', '-O0', '-Werror', #, '-ferror-limit=1', for clang + '-Wfatal-errors'], # for gcc extra_link_args=['-g', '-lrt'], force_generic_engine=True) diff --git a/c7/test/test_list.py b/c7/test/test_list.py --- a/c7/test/test_list.py +++ b/c7/test/test_list.py @@ -56,7 +56,7 @@ ''', define_macros=[('STM_TESTS', '1')], undef_macros=['NDEBUG'], include_dirs=[parent_dir], - extra_compile_args=['-g', '-O0', '-Werror', '-ferror-limit=1'], + extra_compile_args=['-g', '-O0', '-Werror'], #, '-ferror-limit=1'], force_generic_engine=True) # ____________________________________________________________ diff --git a/c7/test/test_rewind.c b/c7/test/test_rewind.c --- a/c7/test/test_rewind.c +++ b/c7/test/test_rewind.c @@ -174,12 +174,26 @@ void foo(int *x) { ++*x; } __attribute__((noinline)) -void f6(int a1, int a2, int a3, int a4, int a5, int a6, int a7, - int a8, int a9, int a10, int a11, int a12, int a13) +void f6(int c1, int c2, int c3, int c4, int c5, int c6, int c7, + int c8, int c9, int c10, int c11, int c12, int c13) { rewind_jmp_buf buf; rewind_jmp_enterframe(>hread, &buf, NULL); + int a1 = c1; + int a2 = c2; + int a3 = c3; + int a4 = c4; + int a5 = c5; + int a6 = c6; + int a7 = c7; + int a8 = c8; + int a9 = c9; + int a10 = c10; + int a11 = c11; + int a12 = c12; + int a13 = c13; + rewind_jmp_setjmp(>hread, NULL); gevent(a1); gevent(a2); gevent(a3); gevent(a4); gevent(a5); gevent(a6); gevent(a7); gevent(a8); diff --git a/c7/test/test_rewind.py b/c7/test/test_rewind.py --- a/c7/test/test_rewind.py +++ b/c7/test/test_rewind.py @@ -1,11 +1,11 @@ import os def run_test(opt): - err = os.system("clang -g -O%s -Werror -DRJBUF_CUSTOM_MALLOC -I../stm" + err = os.system("gcc-seg-gs -g -O%s -Werror -DRJBUF_CUSTOM_MALLOC -I../stm" " -o test_rewind_O%s test_rewind.c ../stm/rewind_setjmp.c" % (opt, opt)) if err != 0: - raise OSError("clang failed on test_rewind.c") + raise OSError("gcc-seg-gs failed on test_rewind.c") for testnum in [1, 2, 3, 4, 5, 6, 7, "TL1", "TL2"]: print '=== O%s: RUNNING TEST %s ===' % (opt, testnum) err = os.system("./test_rewind_O%s %s" % (opt, testnum)) diff --git a/c8/TODO b/c8/TODO --- a/c8/TODO +++ b/c8/TODO @@ -1,3 +1,10 @@ +- stm_identityhash spends a good time figuring out if an obj is prebuilt + (40% of its time). maybe after setup_prebuilt, we could defer the test + of GCFLAG_HAS_SHADOW in id_or_identityhash to after an address comparison. + I.e., after setup_prebuilt, all objs allocated there could be in some + area at the start of the heap, and can thus be classified by having + an address < some_barrier. (may include some non-prebuilt ones, but + that's ok) (also take care of small prebuilt objs) - fix markers (e.g. become_inevitable doesn't seem to show up) diff --git a/c8/demo/Makefile b/c8/demo/Makefile --- a/c8/demo/Makefile +++ b/c8/demo/Makefile @@ -19,18 +19,20 @@ COMMON = -I.. -pthread -lrt -g -Wall -Werror -DSTM_LARGEMALLOC_TEST +CC = gcc-seg-gs + # note that 'build' is partially optimized but still contains all asserts debug-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DSTM_DEBUGPRINT -DSTM_GC_NURSERY=128 -O0 \ + $(CC) $(COMMON) -DSTM_DEBUGPRINT -DSTM_GC_NURSERY=128 -O0 \ $< -o debug-$* ../stmgc.c build-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DSTM_GC_NURSERY=128 -O1 $< -o build-$* ../stmgc.c + $(CC) $(COMMON) -DSTM_GC_NURSERY=128 -O1 $< -o build-$* ../stmgc.c release-%: %.c ${H_FILES} ${C_FILES} - clang $(COMMON) -DNDEBUG -O2 $< -o release-$* ../stmgc.c + $(CC) $(COMMON) -DNDEBUG -O2 $< -o release-$* ../stmgc.c release-htm-%: %.c ../../htm-c7/stmgc.? ../../htm-c7/htm.h - clang $(COMMON) -O2 $< -o release-htm-$* ../../htm-c7/stmgc.c -DUSE_HTM + $(CC) $(COMMON) -O2 $< -o release-htm-$* ../../htm-c7/stmgc.c -DUSE_HTM diff --git a/c8/demo/demo2.c b/c8/demo/demo2.c --- a/c8/demo/demo2.c +++ b/c8/demo/demo2.c @@ -214,7 +214,7 @@ void teardown_list(void) { - STM_POP_ROOT_RET(stm_thread_local); + STM_POP_ROOT_DROP(stm_thread_local); } @@ -255,6 +255,7 @@ stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf); unregister_thread_local(); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } @@ -292,6 +293,7 @@ rewind_jmp_buf rjbuf; status = sem_init(&done, 0, 0); assert(status == 0); + (void)status; stm_setup(); stm_register_thread_local(&stm_thread_local); @@ -308,6 +310,7 @@ for (i = 1; i <= NTHREADS; i++) { status = sem_wait(&done); assert(status == 0); + (void)status; } final_check(); diff --git a/c8/demo/demo_random.c b/c8/demo/demo_random.c --- a/c8/demo/demo_random.c +++ b/c8/demo/demo_random.c @@ -463,6 +463,7 @@ stm_unregister_thread_local(&stm_thread_local); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } diff --git a/c8/demo/demo_random2.c b/c8/demo/demo_random2.c --- a/c8/demo/demo_random2.c +++ b/c8/demo/demo_random2.c @@ -485,6 +485,7 @@ stm_unregister_thread_local(&stm_thread_local); status = sem_post(&done); assert(status == 0); + (void)status; return NULL; } diff --git a/c8/demo/test_shadowstack.c b/c8/demo/test_shadowstack.c --- a/c8/demo/test_shadowstack.c +++ b/c8/demo/test_shadowstack.c @@ -53,7 +53,7 @@ then do a major collection. It should still be found by the tracing logic. */ stm_force_transaction_break(&stm_thread_local); - STM_POP_ROOT_RET(stm_thread_local); + STM_POP_ROOT_DROP(stm_thread_local); STM_POP_ROOT(stm_thread_local, node); assert(node->value == 129821); STM_PUSH_ROOT(stm_thread_local, NULL); diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -12,7 +12,7 @@ { assert(undo->type != TYPE_POSITION_MARKER); free(undo->backup); - assert(undo->backup = (char*)-88); + assert(undo->backup = (char*)0xbb); increment_total_allocated(-SLICE_SIZE(undo->slice)); } @@ -119,6 +119,7 @@ dprintf(("copy_bk_objs_in_page_from(%d, %ld, %d)\n", from_segnum, (long)pagenum, only_if_not_modified)); + assert(modification_lock_check_rdlock(from_segnum)); struct list_s *list = get_priv_segment(from_segnum)->modified_old_objects; struct stm_undo_s *undo = (struct stm_undo_s *)list->items; struct stm_undo_s *end = (struct stm_undo_s *)(list->items + list->count); @@ -238,6 +239,7 @@ addr >= stm_object_pages+TOTAL_MEMORY) { /* actual segfault, unrelated to stmgc */ fprintf(stderr, "Segmentation fault: accessing %p\n", addr); + detect_shadowstack_overflow(addr); abort(); } @@ -269,7 +271,7 @@ /* ############# commit log ############# */ -void _dbg_print_commit_log() +void _dbg_print_commit_log(void) { struct stm_commit_log_entry_s *cl = &commit_log_root; @@ -306,7 +308,7 @@ } } -static void reset_modified_from_backup_copies(int segment_num); /* forward */ +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj); /* forward */ static bool _stm_validate(void) { @@ -407,6 +409,25 @@ if (LIKELY(!_stm_was_read(obj))) continue; + /* check for NO_CONFLICT flag in seg0. While its data may + not be current there, the flag will be there and is + immutable. (we cannot check in my_segnum bc. we may + only have executed stm_read(o) but not touched its pages + yet -> they may be NO_ACCESS */ + struct object_s *obj0 = (struct object_s *)REAL_ADDRESS(get_segment_base(0), obj); + if (obj0->stm_flags & GCFLAG_NO_CONFLICT) { + /* obj is noconflict and therefore shouldn't cause + an abort. However, from now on, we also assume + that an abort would not roll-back to what is in + the backup copy, as we don't trace the bkcpy + during major GCs. + We choose the approach to reset all our changes + to this obj here, so that we can throw away the + backup copy completely: */ + reset_modified_from_backup_copies(my_segnum, obj); + continue; + } + /* conflict! */ dprintf(("_stm_validate() failed for obj %p\n", obj)); @@ -416,7 +437,7 @@ from the old (but unmodified) version to the newer version. */ - reset_modified_from_backup_copies(my_segnum); + reset_modified_from_backup_copies(my_segnum, NULL); timing_write_read_contention(cl->written, undo); needs_abort = true; break; @@ -614,7 +635,8 @@ new = _create_commit_log_entry(); if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) { - assert(_stm_detached_inevitable_from_thread == 0); /* running it */ + assert(_stm_detached_inevitable_from_thread == 0 /* running it */ + || _stm_detached_inevitable_from_thread == -1); /* committing external */ old = STM_PSEGMENT->last_commit_log_entry; new->rev_num = old->rev_num + 1; @@ -868,7 +890,6 @@ _cards_cleared_in_object(get_priv_segment(STM_SEGMENT->segment_num), obj, false); } -__attribute__((always_inline)) static void write_slowpath_overflow_obj(object_t *obj, bool mark_card) { assert(obj->stm_flags & GCFLAG_WRITE_BARRIER); @@ -927,7 +948,6 @@ release_privatization_lock(STM_SEGMENT->segment_num); } -__attribute__((always_inline)) static void write_slowpath_common(object_t *obj, bool mark_card) { assert(_seems_to_be_running_transaction()); @@ -1070,6 +1090,7 @@ obj, index, get_index_to_card_index(index), CARD_MARKED)); } +__attribute__((flatten)) void _stm_write_slowpath(object_t *obj) { write_slowpath_common(obj, /* mark_card */ false); } @@ -1336,6 +1357,16 @@ push_large_overflow_objects_to_other_segments(); /* push before validate. otherwise they are reachable too early */ + + /* before releasing _stm_detached_inevitable_from_thread, perform + the commit. Otherwise, the same thread whose (inev) transaction we try + to commit here may start a new one in another segment *but* w/o + the committed data from its previous inev transaction. (the + stm_validate() at the start of a new transaction is happy even + if there is an inevitable tx running) */ + bool was_inev = STM_PSEGMENT->transaction_state == TS_INEVITABLE; + _validate_and_add_to_commit_log(); + if (external) { /* from this point on, unlink the original 'stm_thread_local_t *' from its segment. Better do it as soon as possible, because @@ -1347,17 +1378,16 @@ _stm_detached_inevitable_from_thread = 0; } - bool was_inev = STM_PSEGMENT->transaction_state == TS_INEVITABLE; - _validate_and_add_to_commit_log(); if (!was_inev) { assert(!external); stm_rewind_jmp_forget(STM_SEGMENT->running_thread); } + commit_finalizers(); + /* XXX do we still need a s_mutex_lock() section here? */ s_mutex_lock(); - commit_finalizers(); /* update 'overflow_number' if needed */ if (STM_PSEGMENT->overflow_number_has_been_used) { @@ -1388,7 +1418,7 @@ invoke_general_finalizers(tl); } -static void reset_modified_from_backup_copies(int segment_num) +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj) { #pragma push_macro("STM_PSEGMENT") #pragma push_macro("STM_SEGMENT") @@ -1404,7 +1434,11 @@ for (; undo < end; undo++) { if (undo->type == TYPE_POSITION_MARKER) continue; + object_t *obj = undo->object; + if (only_obj != NULL && obj != only_obj) + continue; + char *dst = REAL_ADDRESS(pseg->pub.segment_base, obj); memcpy(dst + SLICE_OFFSET(undo->slice), @@ -1416,12 +1450,29 @@ SLICE_SIZE(undo->slice), undo->backup)); free_bk(undo); + + if (only_obj != NULL) { + assert(IMPLY(only_obj != NULL, + (((struct object_s *)dst)->stm_flags + & (GCFLAG_NO_CONFLICT + | GCFLAG_WRITE_BARRIER + | GCFLAG_WB_EXECUTED)) + == (GCFLAG_NO_CONFLICT | GCFLAG_WRITE_BARRIER))); + /* copy last element over this one */ + end--; + list->count -= 3; + if (undo < end) + *undo = *end; + undo--; /* next itr */ + } } - /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ - check_all_write_barrier_flags(pseg->pub.segment_base, list); + if (only_obj == NULL) { + /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ + check_all_write_barrier_flags(pseg->pub.segment_base, list); - list_clear(list); + list_clear(list); + } #pragma pop_macro("STM_SEGMENT") #pragma pop_macro("STM_PSEGMENT") } @@ -1457,7 +1508,7 @@ }); acquire_modification_lock_wr(segment_num); - reset_modified_from_backup_copies(segment_num); + reset_modified_from_backup_copies(segment_num, NULL); release_modification_lock_wr(segment_num); _verify_cards_cleared_in_all_lists(pseg); @@ -1629,6 +1680,16 @@ if (!_validate_and_turn_inevitable()) return; } + + /* There may be a concurrent commit of a detached Tx going on. + Here, we may be right after the _validate_and_add_to_commit_log + and before resetting _stm_detached_inevitable_from_thread to + 0. We have to wait for this to happen bc. otherwise, eg. + _stm_detach_inevitable_transaction is not safe to do yet */ + while (_stm_detached_inevitable_from_thread == -1) + spin_loop(); + assert(_stm_detached_inevitable_from_thread == 0); + soon_finished_or_inevitable_thread_segment(); STM_PSEGMENT->transaction_state = TS_INEVITABLE; diff --git a/c8/stm/core.h b/c8/stm/core.h --- a/c8/stm/core.h +++ b/c8/stm/core.h @@ -43,6 +43,7 @@ GCFLAG_CARDS_SET = _STM_GCFLAG_CARDS_SET, GCFLAG_VISITED = 0x10, GCFLAG_FINALIZATION_ORDERING = 0x20, + GCFLAG_NO_CONFLICT = _STM_GCFLAG_NO_CONFLICT, /* All remaining bits of the 32-bit 'stm_flags' field are taken by the "overflow number". This is a number that identifies the "overflow objects" from the current transaction among all old @@ -50,7 +51,7 @@ current transaction that have been flushed out of the nursery, which occurs if the same transaction allocates too many objects. */ - GCFLAG_OVERFLOW_NUMBER_bit0 = 0x40 /* must be last */ + GCFLAG_OVERFLOW_NUMBER_bit0 = 0x80 /* must be last */ }; #define SYNC_QUEUE_SIZE 31 @@ -267,14 +268,6 @@ return stm_object_pages + segment_num * (NB_PAGES * 4096UL); } -static inline long get_num_segment_containing_address(char *addr) -{ - uintptr_t delta = addr - stm_object_pages; - uintptr_t result = delta / (NB_PAGES * 4096UL); - assert(result < NB_SEGMENTS); - return result; -} - static inline struct stm_segment_info_s *get_segment(long segment_num) { return (struct stm_segment_info_s *)REAL_ADDRESS( diff --git a/c8/stm/detach.c b/c8/stm/detach.c --- a/c8/stm/detach.c +++ b/c8/stm/detach.c @@ -122,6 +122,9 @@ dprintf(("reattach_transaction: commit detached from seg %d\n", remote_seg_num)); + assert(tl != old_tl); + + // XXX: not sure if the next line is a good idea tl->last_associated_segment_num = remote_seg_num; ensure_gs_register(remote_seg_num); commit_external_inevitable_transaction(); @@ -135,6 +138,7 @@ { dprintf(("> stm_force_transaction_break()\n")); assert(STM_SEGMENT->running_thread == tl); + assert(!stm_is_atomic(tl)); _stm_commit_transaction(); _stm_start_transaction(tl); } @@ -180,14 +184,9 @@ dprintf(("commit_fetched_detached_transaction from seg %d\n", segnum)); assert(segnum > 0); - if (segnum != mysegnum) { - set_gs_register(get_segment_base(segnum)); - } + ensure_gs_register(segnum); commit_external_inevitable_transaction(); - - if (segnum != mysegnum) { - set_gs_register(get_segment_base(mysegnum)); - } + ensure_gs_register(mysegnum); } static void commit_detached_transaction_if_from(stm_thread_local_t *tl) diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c --- a/c8/stm/finalizer.c +++ b/c8/stm/finalizer.c @@ -29,6 +29,9 @@ static void _commit_finalizers(void) { /* move finalizer lists to g_finalizers for major collections */ + while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) { + spin_loop(); + } if (STM_PSEGMENT->finalizers->run_finalizers != NULL) { /* copy 'STM_PSEGMENT->finalizers->run_finalizers' into @@ -60,6 +63,8 @@ free(STM_PSEGMENT->finalizers); STM_PSEGMENT->finalizers = NULL; + + __sync_lock_release(&g_finalizers.lock); } static void abort_finalizers(struct stm_priv_segment_info_s *pseg) @@ -309,7 +314,7 @@ { assert(_finalization_state(obj) == 1); /* The call will add GCFLAG_VISITED recursively, thus bump state 1->2 */ - mark_visit_possibly_new_object(obj, pseg); + mark_visit_possibly_overflow_object(obj, pseg); } static struct list_s *mark_finalize_step1( @@ -389,7 +394,7 @@ static void deal_with_objects_with_finalizers(void) { /* for non-light finalizers */ - + assert(_has_mutex()); /* there is one 'objects_with_finalizers' list per segment. Objects that die at a major collection running in the same transaction as they were created will be put in the @@ -431,7 +436,7 @@ if (f != NULL && f->run_finalizers != NULL) { LIST_FOREACH_R(f->run_finalizers, object_t * /*item*/, ({ - mark_visit_possibly_new_object(item, pseg); + mark_visit_possibly_overflow_object(item, pseg); })); } } @@ -481,25 +486,39 @@ LIST_FREE(f->run_finalizers); } +/* XXX: according to translator.backendopt.finalizer, getfield_gc + for primitive types is a safe op in light finalizers. + I don't think that's correct in general (maybe if + getfield on *dying obj*). +*/ + static void _invoke_general_finalizers(stm_thread_local_t *tl) { /* called between transactions */ - static int lock = 0; - - if (__sync_lock_test_and_set(&lock, 1) != 0) { - /* can't acquire the lock: someone else is likely already - running this function, so don't wait. */ - return; - } - rewind_jmp_buf rjbuf; stm_rewind_jmp_enterframe(tl, &rjbuf); _stm_start_transaction(tl); + /* XXX: become inevitable, bc. otherwise, we would need to keep + around the original g_finalizers.run_finalizers to restore it + in case of an abort. */ + _stm_become_inevitable("finalizer-Tx"); - _execute_finalizers(&g_finalizers); + while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) { + /* somebody is adding more finalizers (_commit_finalizer()) */ + spin_loop(); + } + struct finalizers_s copy = g_finalizers; + assert(copy.running_next == NULL); + g_finalizers.run_finalizers = NULL; + /* others may add to g_finalizers again: */ + __sync_lock_release(&g_finalizers.lock); + + if (copy.run_finalizers != NULL) { + _execute_finalizers(©); + } _stm_commit_transaction(); stm_rewind_jmp_leaveframe(tl, &rjbuf); - __sync_lock_release(&lock); + LIST_FREE(copy.run_finalizers); } diff --git a/c8/stm/finalizer.h b/c8/stm/finalizer.h --- a/c8/stm/finalizer.h +++ b/c8/stm/finalizer.h @@ -1,5 +1,7 @@ +/* see deal_with_objects_with_finalizers() for explanation of these fields */ struct finalizers_s { + long lock; struct list_s *objects_with_finalizers; uintptr_t count_non_young; struct list_s *run_finalizers; diff --git a/c8/stm/forksupport.c b/c8/stm/forksupport.c --- a/c8/stm/forksupport.c +++ b/c8/stm/forksupport.c @@ -20,7 +20,7 @@ s_mutex_lock(); dprintf(("forksupport_prepare\n")); - fprintf(stderr, "[forking: for now, this operation can take some time]\n"); + //fprintf(stderr, "[forking: for now, this operation can take some time]\n"); stm_thread_local_t *this_tl = NULL; stm_thread_local_t *tl = stm_all_thread_locals; @@ -87,7 +87,7 @@ assert(tl->last_associated_segment_num == i); assert(in_transaction(tl)); assert(pr->transaction_state != TS_INEVITABLE); - set_gs_register(get_segment_base(i)); + ensure_gs_register(i); assert(STM_SEGMENT->segment_num == i); s_mutex_lock(); @@ -155,7 +155,7 @@ int segnum = fork_this_tl->last_associated_segment_num; assert(1 <= segnum && segnum < NB_SEGMENTS); *_get_cpth(fork_this_tl) = pthread_self(); - set_gs_register(get_segment_base(segnum)); + ensure_gs_register(segnum); assert(STM_SEGMENT->segment_num == segnum); if (!fork_was_in_transaction) { diff --git a/c8/stm/fprintcolor.c b/c8/stm/fprintcolor.c --- a/c8/stm/fprintcolor.c +++ b/c8/stm/fprintcolor.c @@ -1,3 +1,5 @@ +#include + /* ------------------------------------------------------------ */ #ifdef STM_DEBUGPRINT /* ------------------------------------------------------------ */ diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c --- a/c8/stm/gcpage.c +++ b/c8/stm/gcpage.c @@ -341,7 +341,7 @@ } -static void mark_visit_possibly_new_object(object_t *obj, struct stm_priv_segment_info_s *pseg) +static void mark_visit_possibly_overflow_object(object_t *obj, struct stm_priv_segment_info_s *pseg) { /* if newly allocated object, we trace in segment_base, otherwise in the sharing seg0 */ @@ -464,7 +464,7 @@ for (; modified < end; modified++) { if (modified->type == TYPE_POSITION_MARKER && modified->type2 != TYPE_MODIFIED_HASHTABLE) - mark_visit_possibly_new_object(modified->marker_object, pseg); + mark_visit_possibly_overflow_object(modified->marker_object, pseg); } } } @@ -503,11 +503,11 @@ struct stm_shadowentry_s *base = tl->shadowstack_base; while (current-- != base) { if ((((uintptr_t)current->ss) & 3) == 0) { - mark_visit_possibly_new_object(current->ss, pseg); + mark_visit_possibly_overflow_object(current->ss, pseg); } } - mark_visit_possibly_new_object(tl->thread_local_obj, pseg); + mark_visit_possibly_overflow_object(tl->thread_local_obj, pseg); tl = tl->next; } while (tl != stm_all_thread_locals); @@ -517,7 +517,7 @@ assert(get_priv_segment(0)->transaction_state == TS_NONE); for (i = 1; i < NB_SEGMENTS; i++) { if (get_priv_segment(i)->transaction_state != TS_NONE) { - mark_visit_possibly_new_object( + mark_visit_possibly_overflow_object( get_priv_segment(i)->threadlocal_at_start_of_transaction, get_priv_segment(i)); diff --git a/c8/stm/hashtable.c b/c8/stm/hashtable.c --- a/c8/stm/hashtable.c +++ b/c8/stm/hashtable.c @@ -150,8 +150,9 @@ static void _stm_rehash_hashtable(stm_hashtable_t *hashtable, uintptr_t biggercount, - char *segment_base) + long segnum) /* segnum=-1 if no major GC */ { + char *segment_base = segnum == -1 ? NULL : get_segment_base(segnum); dprintf(("rehash %p to size %ld, segment_base=%p\n", hashtable, biggercount, segment_base)); @@ -175,22 +176,28 @@ stm_hashtable_entry_t *entry = table->items[j]; if (entry == NULL) continue; - if (segment_base != NULL) { + + char *to_read_from = segment_base; + if (segnum != -1) { /* -> compaction during major GC */ + /* it's possible that we just created this entry, and it wasn't + touched in this segment yet. Then seg0 is up-to-date. */ + to_read_from = get_page_status_in(segnum, (uintptr_t)entry / 4096UL) == PAGE_NO_ACCESS + ? stm_object_pages : to_read_from; if (((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->object == NULL && - !_stm_was_read_by_anybody((object_t *)entry)) { - dprintf((" removing dead %p\n", entry)); + REAL_ADDRESS(to_read_from, entry))->object == NULL && + !_stm_was_read_by_anybody((object_t *)entry)) { + dprintf((" removing dead %p at %ld\n", entry, j)); continue; } } uintptr_t eindex; - if (segment_base == NULL) + if (segnum == -1) eindex = entry->index; /* read from STM_SEGMENT */ else eindex = ((struct stm_hashtable_entry_s *) - REAL_ADDRESS(segment_base, entry))->index; + REAL_ADDRESS(to_read_from, entry))->index; dprintf((" insert_clean %p at index=%ld\n", entry, eindex)); @@ -222,8 +229,10 @@ i = index & mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found at the first try */ + } uintptr_t perturb = index; while (1) { @@ -231,8 +240,10 @@ i &= mask; entry = VOLATILE_TABLE(table)->items[i]; if (entry != NULL) { - if (entry->index == index) + if (entry->index == index) { + stm_read((object_t*)entry); return entry; /* found */ + } } else break; @@ -285,7 +296,8 @@ if (rc > 6) { /* we can only enter here once! If we allocate stuff, we may run the GC, and so 'hashtableobj' might move afterwards. */ - if (_is_in_nursery(hashtableobj)) { + if (_is_in_nursery(hashtableobj) + && will_allocate_in_nursery(sizeof(stm_hashtable_entry_t))) { /* this also means that the hashtable is from this transaction and not visible to other segments yet, so the new entry can be nursery-allocated. */ @@ -329,6 +341,7 @@ table->items[i] = entry; write_fence(); /* make sure 'table->items' is written here */ VOLATILE_TABLE(table)->resize_counter = rc - 6; /* unlock */ + stm_read((object_t*)entry); return entry; } else { @@ -339,7 +352,7 @@ biggercount *= 4; else biggercount *= 2; - _stm_rehash_hashtable(hashtable, biggercount, /*segment_base=*/NULL); + _stm_rehash_hashtable(hashtable, biggercount, /*segnum=*/-1); goto restart; } } @@ -348,7 +361,7 @@ uintptr_t key) { stm_hashtable_entry_t *e = stm_hashtable_lookup(hobj, hashtable, key); - stm_read((object_t *)e); + // stm_read((object_t *)e); - done in _lookup() return e->object; } @@ -359,6 +372,9 @@ stm_write((object_t *)entry); + /* this restriction may be lifted, see test_new_entry_if_nursery_full: */ + assert(IMPLY(_is_young((object_t *)entry), _is_young(hobj))); + uintptr_t i = list_count(STM_PSEGMENT->modified_old_objects); if (i > 0 && list_item(STM_PSEGMENT->modified_old_objects, i - 3) == (uintptr_t)entry) { @@ -379,11 +395,13 @@ will make the other transaction check that it didn't do any stm_hashtable_list() on the complete hashtable. */ + acquire_modification_lock_wr(STM_SEGMENT->segment_num); STM_PSEGMENT->modified_old_objects = list_append3( STM_PSEGMENT->modified_old_objects, TYPE_POSITION_MARKER, /* type1 */ TYPE_MODIFIED_HASHTABLE, /* type2 */ (uintptr_t)hobj); /* modif_hashtable */ + release_modification_lock_wr(STM_SEGMENT->segment_num); } } entry->object = nvalue; @@ -420,7 +438,7 @@ } long stm_hashtable_list(object_t *hobj, stm_hashtable_t *hashtable, - stm_hashtable_entry_t **results) + stm_hashtable_entry_t * TLPREFIX *results) { /* Set the read marker. It will be left as long as we're running the same transaction. @@ -481,7 +499,7 @@ objects in the segment of the running transaction. Otherwise, the base case is to read them all from segment zero. */ - long segnum = get_num_segment_containing_address((char *)hobj); + long segnum = get_segment_of_linear_address((char *)hobj); if (!IS_OVERFLOW_OBJ(get_priv_segment(segnum), hobj)) segnum = 0; @@ -495,7 +513,7 @@ assert(count <= table->mask + 1); dprintf(("compact with %ld items:\n", num_entries_times_6 / 6)); - _stm_rehash_hashtable(hashtable, count, get_segment_base(segnum)); + _stm_rehash_hashtable(hashtable, count, segnum); } table = hashtable->table; diff --git a/c8/stm/locks.h b/c8/stm/locks.h --- a/c8/stm/locks.h +++ b/c8/stm/locks.h @@ -10,11 +10,14 @@ of modification locks! */ -typedef struct { - pthread_rwlock_t lock; +typedef union { + struct { + pthread_rwlock_t lock; #ifndef NDEBUG - volatile bool write_locked; + volatile bool write_locked; #endif + }; + char _pad[64]; } modification_lock_t __attribute__((aligned(64))); static modification_lock_t _modlocks[NB_SEGMENTS - 1]; diff --git a/c8/stm/marker.c b/c8/stm/marker.c --- a/c8/stm/marker.c +++ b/c8/stm/marker.c @@ -73,12 +73,14 @@ /* -2 is not odd */ assert(marker.odd_number != (uintptr_t)TYPE_MODIFIED_HASHTABLE); + acquire_modification_lock_wr(STM_SEGMENT->segment_num); STM_PSEGMENT->position_markers_last = list_count(list); STM_PSEGMENT->modified_old_objects = list_append3( list, TYPE_POSITION_MARKER, /* type */ marker.odd_number, /* marker_odd_number */ (uintptr_t)marker.object); /* marker_object */ + release_modification_lock_wr(STM_SEGMENT->segment_num); } static void timing_write_read_contention(struct stm_undo_s *start, diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c --- a/c8/stm/nursery.c +++ b/c8/stm/nursery.c @@ -477,6 +477,7 @@ /* reset the nursery by zeroing it */ char *realnursery; realnursery = REAL_ADDRESS(pseg->pub.segment_base, _stm_nursery_start); + (void)realnursery; #if _STM_NURSERY_ZEROED memset(realnursery, 0, nursery_used); @@ -722,7 +723,7 @@ /* including the sharing seg0 */ for (i = 0; i < NB_SEGMENTS; i++) { - set_gs_register(get_segment_base(i)); + ensure_gs_register(i); bool ok = _stm_validate(); assert(get_priv_segment(i)->last_commit_log_entry->next == NULL @@ -768,7 +769,7 @@ } } - set_gs_register(get_segment_base(original_num)); + ensure_gs_register(original_num); } @@ -777,8 +778,16 @@ char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj); size_t size = stmcb_size_rounded_up((struct object_s *)realobj); - /* always gets outside as a large object for now (XXX?) */ - object_t *nobj = (object_t *)allocate_outside_nursery_large(size); + /* always gets outside */ + object_t *nobj; + if (size > GC_LAST_SMALL_SIZE) { + /* case 1: object is not small enough. + Ask gcpage.c for an allocation via largemalloc. */ + nobj = (object_t *)allocate_outside_nursery_large(size); + } else { + /* case "small enough" */ + nobj = (object_t *)allocate_outside_nursery_small(size); + } /* Initialize the shadow enough to be considered a valid gc object. If the original object stays alive at the next minor collection, diff --git a/c8/stm/nursery.h b/c8/stm/nursery.h --- a/c8/stm/nursery.h +++ b/c8/stm/nursery.h @@ -27,6 +27,20 @@ get_priv_segment(other_segment_num)->safe_point != SP_RUNNING); } +static inline bool will_allocate_in_nursery(size_t size_rounded_up) { + OPT_ASSERT(size_rounded_up >= 16); + OPT_ASSERT((size_rounded_up & 7) == 0); + + if (UNLIKELY(size_rounded_up >= _STM_FAST_ALLOC)) + return false; + + stm_char *p = STM_SEGMENT->nursery_current; + stm_char *end = p + size_rounded_up; + if (UNLIKELY((uintptr_t)end > STM_SEGMENT->nursery_end)) + return false; + return true; +} + #define must_abort() is_abort(STM_SEGMENT->nursery_end) static object_t *find_shadow(object_t *obj); diff --git a/c8/stm/pages.c b/c8/stm/pages.c --- a/c8/stm/pages.c +++ b/c8/stm/pages.c @@ -28,7 +28,7 @@ uint64_t ta = __sync_add_and_fetch(&pages_ctl.total_allocated, add_or_remove); - if (ta >= pages_ctl.total_allocated_bound) + if (UNLIKELY(ta >= pages_ctl.total_allocated_bound)) pages_ctl.major_collection_requested = true; return ta; diff --git a/c8/stm/queue.c b/c8/stm/queue.c --- a/c8/stm/queue.c +++ b/c8/stm/queue.c @@ -52,7 +52,7 @@ stm_queue_t *stm_queue_create(void) { - void *mem; + void *mem = NULL; int result = posix_memalign(&mem, 64, sizeof(stm_queue_t)); assert(result == 0); (void)result; @@ -437,7 +437,7 @@ queue_entry_t *entry = seg->added_in_this_transaction; while (entry != NULL) { - mark_visit_possibly_new_object(entry->object, pseg); + mark_visit_possibly_overflow_object(entry->object, pseg); entry = entry->next; } } TREE_LOOP_END; diff --git a/c8/stm/setup.c b/c8/stm/setup.c --- a/c8/stm/setup.c +++ b/c8/stm/setup.c @@ -183,12 +183,12 @@ teardown_modification_locks(); } -static void _shadowstack_trap_page(char *start, int prot) +static char *_shadowstack_trap_page(struct stm_shadowentry_s *base) { size_t bsize = STM_SHADOW_STACK_DEPTH * sizeof(struct stm_shadowentry_s); - char *end = start + bsize + 4095; + char *end = ((char *)base) + bsize + 4095; end -= (((uintptr_t)end) & 4095); - mprotect(end, 4096, prot); + return end; } static void _init_shadow_stack(stm_thread_local_t *tl) @@ -200,9 +200,9 @@ /* set up a trap page: if the shadowstack overflows, it will crash in a clean segfault */ - _shadowstack_trap_page(start, PROT_NONE); + struct stm_shadowentry_s *s = (struct stm_shadowentry_s *)start; + mprotect(_shadowstack_trap_page(s), 4096, PROT_NONE); - struct stm_shadowentry_s *s = (struct stm_shadowentry_s *)start; tl->shadowstack = s; tl->shadowstack_base = s; STM_PUSH_ROOT(*tl, -1); @@ -213,8 +213,8 @@ assert(tl->shadowstack > tl->shadowstack_base); assert(tl->shadowstack_base->ss == (object_t *)-1); - char *start = (char *)tl->shadowstack_base; - _shadowstack_trap_page(start, PROT_READ | PROT_WRITE); + char *trap = _shadowstack_trap_page(tl->shadowstack_base); + mprotect(trap, 4096, PROT_READ | PROT_WRITE); free(tl->shadowstack_base); tl->shadowstack = NULL; @@ -295,3 +295,19 @@ { return tl->next != NULL; } + +static void detect_shadowstack_overflow(char *addr) +{ + if (addr == NULL) + return; + stm_thread_local_t *tl = stm_all_thread_locals; + while (tl != NULL) { + char *trap = _shadowstack_trap_page(tl->shadowstack_base); + if (trap <= addr && addr <= trap + 4095) { + fprintf(stderr, "This is caused by a stack overflow.\n" + "Sorry, proper RuntimeError support is not implemented yet.\n"); + return; + } + tl = tl->next; + } +} diff --git a/c8/stm/setup.h b/c8/stm/setup.h --- a/c8/stm/setup.h +++ b/c8/stm/setup.h @@ -1,6 +1,7 @@ static void setup_mmap(char *reason); static void setup_protection_settings(void); static pthread_t *_get_cpth(stm_thread_local_t *); +static void detect_shadowstack_overflow(char *); #ifndef NDEBUG static __thread long _stm_segfault_expected = 1; diff --git a/c8/stm/smallmalloc.c b/c8/stm/smallmalloc.c --- a/c8/stm/smallmalloc.c +++ b/c8/stm/smallmalloc.c @@ -8,9 +8,9 @@ typedef struct { uint8_t sz; -} fpsz_t; +} full_page_size_t; -static fpsz_t full_pages_object_size[PAGE_SMSIZE_END - PAGE_SMSIZE_START]; +static full_page_size_t full_pages_object_size[PAGE_SMSIZE_END - PAGE_SMSIZE_START]; /* ^^^ This array contains the size (in number of words) of the objects in the given page, provided it's a "full page of small objects". It is 0 if it's not such a page, if it's fully free, or if it's in @@ -19,7 +19,7 @@ technically full yet, it will be very soon in this case). */ -static fpsz_t *get_fpsz(char *smallpage) +static full_page_size_t *get_full_page_size(char *smallpage) { uintptr_t pagenum = (((char *)smallpage) - END_NURSERY_PAGE * 4096UL - stm_object_pages) / 4096; /* <= PAGE_SMSIZE_END because we may ask for it when there is no @@ -118,7 +118,7 @@ /* Succeeded: we have a page in 'smallpage' */ *fl = smallpage->next; - get_fpsz((char *)smallpage)->sz = n; + get_full_page_size((char *)smallpage)->sz = n; return (char *)smallpage; } @@ -126,12 +126,15 @@ Maybe we can pick one from free_uniform_pages. */ smallpage = free_uniform_pages; - if (smallpage != NULL) { + if (LIKELY(smallpage != NULL)) { if (UNLIKELY(!__sync_bool_compare_and_swap(&free_uniform_pages, smallpage, smallpage->nextpage))) goto retry; + /* got a new page: */ + increment_total_allocated(4096); + /* Succeeded: we have a page in 'smallpage', which is not initialized so far, apart from the 'nextpage' field read above. Initialize it. @@ -153,7 +156,7 @@ *previous = NULL; /* The first slot is immediately returned */ - get_fpsz((char *)smallpage)->sz = n; + get_full_page_size((char *)smallpage)->sz = n; return (char *)smallpage; } @@ -174,8 +177,6 @@ struct small_free_loc_s *result = *fl; - increment_total_allocated(size); - if (UNLIKELY(result == NULL)) { char *addr = _allocate_small_slowpath(size); ((struct object_s*)addr)->stm_flags = 0; @@ -270,7 +271,6 @@ } else if (!_smallmalloc_sweep_keep(p)) { /* the location should be freed now */ - increment_total_allocated(-szword*8); #ifdef STM_TESTS /* fill location with 0xdd in all segs except seg0 */ int j; @@ -300,6 +300,7 @@ any_object_remaining = true; } } + if (!any_object_remaining) { /* give page back to free_uniform_pages and thus make it inaccessible from all other segments again (except seg0) */ @@ -311,9 +312,14 @@ ((struct small_free_loc_s *)baseptr)->nextpage = free_uniform_pages; free_uniform_pages = (struct small_free_loc_s *)baseptr; + + /* gave the page back */ + increment_total_allocated(-4096); } else if (!any_object_dying) { - get_fpsz(baseptr)->sz = szword; + /* this is still a full page. only in this case we set the + full_page_size again: */ + get_full_page_size(baseptr)->sz = szword; } else { check_order_inside_small_page(page_free); @@ -339,9 +345,9 @@ if (*fl != NULL) { /* the entry in full_pages_object_size[] should already be szword. We reset it to 0. */ - fpsz_t *fpsz = get_fpsz((char *)*fl); - assert(fpsz->sz == szword); - fpsz->sz = 0; + full_page_size_t *full_page_size = get_full_page_size((char *)*fl); + assert(full_page_size->sz == szword); + full_page_size->sz = 0; sweep_small_page(getbaseptr(*fl), *fl, szword); *fl = NULL; } @@ -351,7 +357,7 @@ while (page != NULL) { /* for every page in small_page_lists: assert that the corresponding full_pages_object_size[] entry is 0 */ - assert(get_fpsz((char *)page)->sz == 0); + assert(get_full_page_size((char *)page)->sz == 0); nextpage = page->nextpage; sweep_small_page(getbaseptr(page), page, szword); page = nextpage; @@ -361,10 +367,10 @@ /* process the really full pages, which are the ones which still have a non-zero full_pages_object_size[] entry */ char *pageptr = uninitialized_page_stop; - fpsz_t *fpsz_start = get_fpsz(pageptr); - fpsz_t *fpsz_end = &full_pages_object_size[PAGE_SMSIZE_END - - PAGE_SMSIZE_START]; - fpsz_t *fpsz; + full_page_size_t *fpsz_start = get_full_page_size(pageptr); + full_page_size_t *fpsz_end = &full_pages_object_size[PAGE_SMSIZE_END - + PAGE_SMSIZE_START]; + full_page_size_t *fpsz; for (fpsz = fpsz_start; fpsz < fpsz_end; fpsz++, pageptr += 4096) { uint8_t sz = fpsz->sz; if (sz != 0) { diff --git a/c8/stm/sync.c b/c8/stm/sync.c --- a/c8/stm/sync.c +++ b/c8/stm/sync.c @@ -66,7 +66,6 @@ static void ensure_gs_register(long segnum) { - /* XXX use this instead of set_gs_register() in many places */ if (STM_SEGMENT->segment_num != segnum) { set_gs_register(get_segment_base(segnum)); assert(STM_SEGMENT->segment_num == segnum); @@ -211,16 +210,12 @@ assert(_has_mutex()); assert(_is_tl_registered(tl)); - int num = tl->last_associated_segment_num - 1; // 0..NB_SEG-1 + int num = tl->last_associated_segment_num - 1; // 0..NB_SEG-2 OPT_ASSERT(num >= 0); if (sync_ctl.in_use1[num+1] == 0) { /* fast-path: we can get the same segment number than the one - we had before. The value stored in GS is still valid. */ -#ifdef STM_TESTS - /* that can be optimized away, except during tests, because - they use only one thread */ - set_gs_register(get_segment_base(num+1)); -#endif + we had before. The value stored in GS may still be valid. */ + ensure_gs_register(num+1); dprintf(("acquired same segment: %d\n", num+1)); goto got_num; } @@ -234,7 +229,7 @@ int old_num = tl->last_associated_segment_num; dprintf(("acquired different segment: %d->%d\n", old_num, num+1)); tl->last_associated_segment_num = num+1; - set_gs_register(get_segment_base(num+1)); + ensure_gs_register(num+1); dprintf((" %d->%d\n", old_num, num+1)); (void)old_num; goto got_num; @@ -313,14 +308,14 @@ void _stm_test_switch(stm_thread_local_t *tl) { assert(_stm_in_transaction(tl)); - set_gs_register(get_segment_base(tl->last_associated_segment_num)); + ensure_gs_register(tl->last_associated_segment_num); assert(STM_SEGMENT->running_thread == tl); exec_local_finalizers(); } void _stm_test_switch_segment(int segnum) { - set_gs_register(get_segment_base(segnum+1)); + ensure_gs_register(segnum+1); } #if STM_TESTS diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -21,7 +21,15 @@ #endif -#define TLPREFIX __attribute__((address_space(256))) +#ifdef __SEG_GS /* on a custom patched gcc */ +# define TLPREFIX __seg_gs +# define _STM_RM_SUFFIX :8 +#elif defined(__clang__) /* on a clang, hopefully made bug-free */ +# define TLPREFIX __attribute__((address_space(256))) +# define _STM_RM_SUFFIX /* nothing */ +#else +# error "needs either a GCC with __seg_gs support, or a bug-freed clang" +#endif typedef TLPREFIX struct object_s object_t; typedef TLPREFIX struct stm_segment_info_s stm_segment_info_t; @@ -35,18 +43,18 @@ 'STM_SEGMENT->transaction_read_version' if and only if the object was read in the current transaction. The nurseries also have corresponding read markers, but they are never used. */ - uint8_t rm; + unsigned char rm _STM_RM_SUFFIX; }; struct stm_segment_info_s { - uint8_t transaction_read_version; - uint8_t no_safe_point_here; /* set from outside, triggers an assert */ + unsigned int transaction_read_version; int segment_num; char *segment_base; stm_char *nursery_current; stm_char *nursery_mark; uintptr_t nursery_end; struct stm_thread_local_s *running_thread; + uint8_t no_safe_point_here; /* set from outside, triggers an assert */ }; #define STM_SEGMENT ((stm_segment_info_t *)4352) @@ -154,6 +162,7 @@ #endif #define _STM_GCFLAG_WRITE_BARRIER 0x01 +#define _STM_GCFLAG_NO_CONFLICT 0x40 #define _STM_FAST_ALLOC (66*1024) #define _STM_NSE_SIGNAL_ABORT 1 #define _STM_NSE_SIGNAL_MAX 2 @@ -357,6 +366,7 @@ #define STM_PUSH_ROOT(tl, p) ((tl).shadowstack++->ss = (object_t *)(p)) #define STM_POP_ROOT(tl, p) ((p) = (typeof(p))((--(tl).shadowstack)->ss)) #define STM_POP_ROOT_RET(tl) ((--(tl).shadowstack)->ss) +#define STM_POP_ROOT_DROP(tl) ((void)(--(tl).shadowstack)) /* Every thread needs to have a corresponding stm_thread_local_t structure. It may be a "__thread" global variable or something else. @@ -370,7 +380,12 @@ /* At some key places, like the entry point of the thread and in the function with the interpreter's dispatch loop, you need to declare - a local variable of type 'rewind_jmp_buf' and call these macros. */ + a local variable of type 'rewind_jmp_buf' and call these macros. + IMPORTANT: a function in which you call stm_rewind_jmp_enterframe() + must never change the value of its own arguments! If they are + passed on the stack, gcc can change the value directly there, but + we're missing the logic to save/restore this part! +*/ #define stm_rewind_jmp_enterprepframe(tl, rjbuf) \ rewind_jmp_enterprepframe(&(tl)->rjthread, rjbuf, (tl)->shadowstack) #define stm_rewind_jmp_enterframe(tl, rjbuf) \ @@ -657,7 +672,7 @@ #define STM_POP_MARKER(tl) ({ \ object_t *_popped = STM_POP_ROOT_RET(tl); \ - STM_POP_ROOT_RET(tl); \ + STM_POP_ROOT_DROP(tl); \ _popped; \ }) @@ -711,6 +726,9 @@ stm_hashtable_t *stm_hashtable_create(void); void stm_hashtable_free(stm_hashtable_t *); +/* lookup returns a reference to an entry. This entry is only valid + in the current transaction and needs to be looked up again if there + may have been a break inbetween. */ stm_hashtable_entry_t *stm_hashtable_lookup(object_t *, stm_hashtable_t *, uintptr_t key); object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key); @@ -719,8 +737,13 @@ void stm_hashtable_write_entry(object_t *hobj, stm_hashtable_entry_t *entry, object_t *nvalue); long stm_hashtable_length_upper_bound(stm_hashtable_t *); + +/* WARNING: stm_hashtable_list does not do a stm_write() on the 'results' + argument. 'results' may point inside an object. So if 'results' may be + a part of an old obj (which may have survived a minor GC), then make + sure to call stm_write() on the obj before calling this function. */ long stm_hashtable_list(object_t *, stm_hashtable_t *, - stm_hashtable_entry_t **results); + stm_hashtable_entry_t * TLPREFIX *results); extern uint32_t stm_hashtable_entry_userdata; void stm_hashtable_tracefn(struct object_s *, stm_hashtable_t *, void (object_t **)); @@ -758,13 +781,31 @@ void stm_queue_tracefn(stm_queue_t *queue, void trace(object_t **)); + +/* stm_allocate_noconflict() allocates a special kind of object. Validation + will never detect conflicts on such an object. However, writes to it can + get lost. More precisely: every possible point for validation during a + transaction may import a committed version of such objs, thereby resetting + it or even contain not-yet-seen values from other (committed) transactions. + Hence, changes to such an obj that a transaction commits may or may not + propagate to other transactions. */ +__attribute__((always_inline)) +static inline object_t *stm_allocate_noconflict(ssize_t size_rounded_up) +{ + object_t *o = stm_allocate(size_rounded_up); + o->stm_flags |= _STM_GCFLAG_NO_CONFLICT; + return o; +} + + + /* ==================== END ==================== */ -static void (*stmcb_expand_marker)(char *segment_base, uintptr_t odd_number, +extern void (*stmcb_expand_marker)(char *segment_base, uintptr_t odd_number, object_t *following_object, char *outputbuf, size_t outputbufsize); -static void (*stmcb_debug_print)(const char *cause, double time, +extern void (*stmcb_debug_print)(const char *cause, double time, const char *marker); #endif diff --git a/c8/test/common.py b/c8/test/common.py --- a/c8/test/common.py +++ b/c8/test/common.py @@ -3,7 +3,7 @@ assert sys.maxint == 9223372036854775807, "requires a 64-bit environment" # ---------- -os.environ['CC'] = 'clang' +os.environ['CC'] = 'gcc-seg-gs' parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/c8/test/support.py b/c8/test/support.py --- a/c8/test/support.py +++ b/c8/test/support.py @@ -12,6 +12,8 @@ #define _STM_FAST_ALLOC ... #define _STM_CARD_SIZE ... #define _STM_CARD_MARKED ... +#define STM_GC_NURSERY ... +#define SIZEOF_HASHTABLE_ENTRY ... typedef struct { ...; @@ -43,6 +45,7 @@ object_t *stm_allocate(ssize_t size_rounded_up); object_t *stm_allocate_weakref(ssize_t size_rounded_up); object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up); +object_t *stm_allocate_noconflict(ssize_t size_rounded_up); /*void stm_write_card(); use _checked_stm_write_card() instead */ @@ -209,17 +212,21 @@ object_t *hashtable_read_result; bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key, object_t *nvalue, stm_thread_local_t *tl); +stm_hashtable_entry_t *stm_hashtable_lookup(object_t *hashtableobj, + stm_hashtable_t *hashtable, + uintptr_t index); long stm_hashtable_length_upper_bound(stm_hashtable_t *); -long stm_hashtable_list(object_t *, stm_hashtable_t *, - stm_hashtable_entry_t **results); uint32_t stm_hashtable_entry_userdata; void stm_hashtable_tracefn(struct object_s *, stm_hashtable_t *, void trace(object_t **)); +long _stm_hashtable_list(object_t *o, stm_hashtable_t *h, + object_t *entries); void _set_hashtable(object_t *obj, stm_hashtable_t *h); stm_hashtable_t *_get_hashtable(object_t *obj); uintptr_t _get_entry_index(stm_hashtable_entry_t *entry); object_t *_get_entry_object(stm_hashtable_entry_t *entry); +void *_get_hashtable_table(stm_hashtable_t *h); typedef struct stm_queue_s stm_queue_t; stm_queue_t *stm_queue_create(void); @@ -256,6 +263,7 @@ typedef TLPREFIX struct myobj_s myobj_t; #define SIZEOF_MYOBJ sizeof(struct myobj_s) +#define SIZEOF_HASHTABLE_ENTRY sizeof(struct stm_hashtable_entry_s) int _stm_get_flags(object_t *obj) { return obj->stm_flags; @@ -397,6 +405,21 @@ return entry->object; } + +void *_get_hashtable_table(stm_hashtable_t *h) { + return *((void**)h); +} + +long _stm_hashtable_list(object_t *o, stm_hashtable_t *h, + object_t *entries) +{ + if (entries != NULL) + return stm_hashtable_list(o, h, + (stm_hashtable_entry_t * TLPREFIX*)((stm_char*)entries+SIZEOF_MYOBJ)); + return stm_hashtable_list(o, h, NULL); +} + + void _set_queue(object_t *obj, stm_queue_t *q) { stm_char *field_addr = ((stm_char*)obj); @@ -570,11 +593,12 @@ ('STM_NO_COND_WAIT', '1'), ('STM_DEBUGPRINT', '1'), ('_STM_NURSERY_ZEROED', '1'), + ('STM_GC_NURSERY', '128'), # KB ('GC_N_SMALL_REQUESTS', str(GC_N_SMALL_REQUESTS)), #check ], undef_macros=['NDEBUG'], include_dirs=[parent_dir], - extra_compile_args=['-g', '-O0', '-Wall', '-ferror-limit=5'], + extra_compile_args=['-g', '-O0', '-Werror', '-Wall'], #, '-ferror-limit=5'], extra_link_args=['-g', '-lrt'], force_generic_engine=True) @@ -590,7 +614,8 @@ CARD_MARKED = lib._STM_CARD_MARKED CARD_MARKED_OLD = lib._stm_get_transaction_read_version lib.stm_hashtable_entry_userdata = 421418 - +NURSERY_SIZE = lib.STM_GC_NURSERY * 1024 # bytes +SIZEOF_HASHTABLE_ENTRY = lib.SIZEOF_HASHTABLE_ENTRY class Conflict(Exception): pass @@ -640,6 +665,18 @@ lib._set_type_id(o, tid) return o +def stm_allocate_noconflict(size): + o = lib.stm_allocate_noconflict(size) + tid = 42 + size + lib._set_type_id(o, tid) + return o + +def stm_allocate_noconflict_refs(n): + o = lib.stm_allocate_noconflict(HDR + n * WORD) + tid = 421420 + n + lib._set_type_id(o, tid) + return o + def stm_allocate_with_finalizer(size): o = lib.stm_allocate_with_finalizer(size) tid = 42 + size @@ -652,14 +689,20 @@ lib._set_type_id(o, tid) return o +SIZEOF_HASHTABLE_OBJ = 16 + lib.SIZEOF_MYOBJ def stm_allocate_hashtable(): o = lib.stm_allocate(16) + assert is_in_nursery(o) tid = 421419 lib._set_type_id(o, tid) h = lib.stm_hashtable_create() lib._set_hashtable(o, h) return o +def hashtable_lookup(hto, ht, idx): + return ffi.cast("object_t*", + lib.stm_hashtable_lookup(hto, ht, idx)) + def get_hashtable(o): assert lib._get_type_id(o) == 421419 h = lib._get_hashtable(o) @@ -897,6 +940,17 @@ def switch_to_segment(self, seg_num): lib._stm_test_switch_segment(seg_num) + def push_roots(self, os): + for o in os: + self.push_root(o) + self._last_push_all = os + + def pop_roots(self): + os = self._last_push_all + self._last_push_all = None + return list(reversed([self.pop_root() for _ in os])) + + def push_root(self, o): assert ffi.typeof(o) == ffi.typeof("object_t *") tl = self.tls[self.current_thread] diff --git a/c8/test/test_finalizer.py b/c8/test/test_finalizer.py --- a/c8/test/test_finalizer.py +++ b/c8/test/test_finalizer.py @@ -139,6 +139,7 @@ self.expect_finalized([lp1], from_tlnum=0) + class TestRegularFinalizer(BaseTest): expect_content_character = None run_major_collect_in_finalizer = False diff --git a/c8/test/test_gcpage.py b/c8/test/test_gcpage.py --- a/c8/test/test_gcpage.py +++ b/c8/test/test_gcpage.py @@ -325,9 +325,10 @@ actual_big = (big + 15 ) & ~15 self.start_transaction() - assert lib._stm_total_allocated() == 64 + (actual_big + LMO) # large malloc'd + # 4096 for 1 page of smallmalloc: + assert lib._stm_total_allocated() == 4096 + (actual_big + LMO) # large malloc'd stm_major_collect() - assert lib._stm_total_allocated() == 64 + (actual_big + LMO) # large malloc'd + assert lib._stm_total_allocated() == 4096 + (actual_big + LMO) # large malloc'd self.commit_transaction() def test_bug(self): @@ -376,19 +377,19 @@ assert lib._stm_total_allocated() == 0 self.push_root(new) stm_minor_collect() - assert lib._stm_total_allocated() == 16 + assert lib._stm_total_allocated() == 4096 new = self.pop_root() assert not is_in_nursery(new) stm_minor_collect() - assert lib._stm_total_allocated() == 16 + assert lib._stm_total_allocated() == 4096 stm_major_collect() assert lib._stm_total_allocated() == 0 def test_mixed_major_collections(self): import random - obj_sizes = [16, 48, 1024, 1000*8] + obj_sizes = [1024, 1000*8] self.start_transaction() random.seed(123) @@ -398,11 +399,7 @@ NOBJS = 100 for _ in range(NOBJS): osize = random.choice(obj_sizes) - is_small = osize <= GC_LAST_SMALL_SIZE - if is_small: - allocated += osize - else: - allocated += osize + LMO + allocated += osize + LMO o = stm_allocate(osize) self.push_root(o) diff --git a/c8/test/test_hashtable.py b/c8/test/test_hashtable.py --- a/c8/test/test_hashtable.py +++ b/c8/test/test_hashtable.py @@ -23,15 +23,17 @@ def htitems(o): h = get_hashtable(o) upper_bound = lib.stm_hashtable_length_upper_bound(h) - entries = ffi.new("stm_hashtable_entry_t *[]", upper_bound) - count = lib.stm_hashtable_list(o, h, entries) + entries = stm_allocate_refs(upper_bound) + count = lib._stm_hashtable_list(o, h, entries) assert count <= upper_bound - return [(lib._get_entry_index(entries[i]), - lib._get_entry_object(entries[i])) for i in range(count)] + + return [(lib._get_entry_index(ffi.cast("stm_hashtable_entry_t *", stm_get_ref(entries, i))), + lib._get_entry_object(ffi.cast("stm_hashtable_entry_t *", stm_get_ref(entries, i)))) + for i in range(count)] def htlen(o): h = get_hashtable(o) - count = lib.stm_hashtable_list(o, h, ffi.NULL) + count = lib._stm_hashtable_list(o, h, ffi.NULL) return count @@ -352,6 +354,111 @@ stm_major_collect() # to get rid of the hashtable object + def test_new_entry_if_nursery_full(self): + self.start_transaction() + tl0 = self.tls[self.current_thread] + # make sure we fill the nursery *exactly* so that + # the last entry allocation triggers a minor GC + # and needs to allocate preexisting outside the nursery: + SMALL = 24 + lib.SIZEOF_MYOBJ + assert (NURSERY_SIZE - SIZEOF_HASHTABLE_OBJ) % SMALL < SIZEOF_HASHTABLE_ENTRY + to_alloc = (NURSERY_SIZE - SIZEOF_HASHTABLE_OBJ) // SMALL + for i in range(to_alloc): + stm_allocate(SMALL) + h = self.allocate_hashtable() + assert is_in_nursery(h) + self.push_root(h) + # would trigger minor GC when allocating 'entry' in nursery: + entry = hashtable_lookup(h, get_hashtable(h), 123) + h = self.pop_root() + self.push_root(h) + assert is_in_nursery(h) # didn't trigger minor-gc, since entry allocated outside + assert not is_in_nursery(entry) + assert htget(h, 123) == ffi.NULL + htset(h, 123, h, tl0) + + # stm_write(h) - the whole thing may be fixed also by ensuring + # the hashtable gets retraced in minor-GC if stm_hashtable_write_entry + # detects the 'entry' to be young (and hobj being old) + + stm_minor_collect() + h = self.pop_root() + assert htget(h, 123) == h + entry2 = hashtable_lookup(h, get_hashtable(h), 123) + assert entry == entry2 + assert not is_in_nursery(h) + assert not is_in_nursery(entry2) + + # get rid of ht: + self.commit_transaction() + self.start_transaction() + stm_major_collect() + self.commit_transaction() + + def test_dont_lose_entry(self): + self.start_transaction() + h = self.allocate_hashtable() + self.push_root(h) + stm_minor_collect() + h = self.pop_root() + self.push_root(h) + # produce entries: + K = 300 + for i in range(K): + hashtable_lookup(h, get_hashtable(h), i) + + table = lib._get_hashtable_table(get_hashtable(h)) + entry = hashtable_lookup(h, get_hashtable(h), K) + self.push_root(entry) + stm_major_collect() + entry2 = hashtable_lookup(h, get_hashtable(h), K) + entry = self.pop_root() + assert table != lib._get_hashtable_table(get_hashtable(h)) # compacted + assert entry == entry2 + + # get rid of ht: + self.pop_root() + self.commit_transaction() + self.start_transaction() + stm_major_collect() + self.commit_transaction() + + def test_empty_entry_not_kept_alive(self): + self.start_transaction() + h = self.allocate_hashtable() + self.push_root(h) + stm_minor_collect() + h = self.pop_root() + self.push_root(h) From noreply at buildbot.pypy.org Wed Sep 16 12:08:35 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 16 Sep 2015 12:08:35 +0200 (CEST) Subject: [pypy-commit] benchmarks default: Add a benchmark I've been usingx Message-ID: <20150916100835.DB79E1C1E7B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r335:dd58de44c351 Date: 2015-09-16 12:08 +0200 http://bitbucket.org/pypy/benchmarks/changeset/dd58de44c351/ Log: Add a benchmark I've been usingx diff --git a/warmup/tracing_blackholing.py b/warmup/tracing_blackholing.py new file mode 100644 --- /dev/null +++ b/warmup/tracing_blackholing.py @@ -0,0 +1,39 @@ + +for k in range(100): + d = locals().copy() + exec """ + +class A(object): + def __init__(self, a, b, c): + self.a = a + self.b = b + self.c = c + +class B(object): + def __init__(self, a, b): + self.a = a + self.b = b + +def f(count): + s = 0 + l_glob = [None] + for i in range(count): + a = A(1, 2, 3) + if i > 1041: + s += 1 + g(i) + #if i % 15 == 0: + # s += 1 + #if i % 21 == 0: + # s += 1 + l = [a, B(2, 3), a] + l_glob[0] = l[-1] + s += i + return s + +# 1243 = tracing + blackholing + tracing +# 1241 = tracing + blackholing +# 1041 = tracing +# 1039 = just interpreter +f(1243) +""" in d From noreply at buildbot.pypy.org Wed Sep 16 12:08:38 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 16 Sep 2015 12:08:38 +0200 (CEST) Subject: [pypy-commit] benchmarks default: mispaste Message-ID: <20150916100838.3A34A1C1E7B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r336:60a3638f52f4 Date: 2015-09-16 12:09 +0200 http://bitbucket.org/pypy/benchmarks/changeset/60a3638f52f4/ Log: mispaste diff --git a/own/pypy_interp.py b/own/pypy_interp.py --- a/own/pypy_interp.py +++ b/own/pypy_interp.py @@ -26,8 +26,8 @@ l = [] space = gettestobjspace() # warmup - bench(space) - bench(space) + #bench(space) + #bench(space) for i in range(n): t0 = time.time() bench(space) diff --git a/warmup/pypy-graph-alloc-removal.py b/warmup/pypy-graph-alloc-removal.py --- a/warmup/pypy-graph-alloc-removal.py +++ b/warmup/pypy-graph-alloc-removal.py @@ -43,4 +43,4 @@ remover.remove_mallocs_once(g) return time.time() - start -main(graph, 500) +main(graph, 100) diff --git a/warmup/tracing_blackholing.py b/warmup/tracing_blackholing.py --- a/warmup/tracing_blackholing.py +++ b/warmup/tracing_blackholing.py @@ -21,7 +21,6 @@ a = A(1, 2, 3) if i > 1041: s += 1 - g(i) #if i % 15 == 0: # s += 1 #if i % 21 == 0: From noreply at buildbot.pypy.org Wed Sep 16 14:03:01 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 16 Sep 2015 14:03:01 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: scheduling tests passing again Message-ID: <20150916120301.578D91C0148@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79651:5b32b72ad145 Date: 2015-09-16 14:02 +0200 http://bitbucket.org/pypy/pypy/changeset/5b32b72ad145/ Log: scheduling tests passing again diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -70,13 +70,14 @@ return True return node.depends_count() != 0 - def mark_emitted(self, node, state): + def mark_emitted(self, node, state, unpack=True): """ An operation has been emitted, adds new operations to the worklist whenever their dependency count drops to zero. Keeps worklist sorted (see priority) """ op = node.getoperation() state.renamer.rename(op) - state.ensure_args_unpacked(op) + if unpack: + state.ensure_args_unpacked(op) node.position = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY @@ -322,7 +323,7 @@ rop.UINT_LT, rop.UINT_LE, rop.UINT_GT, rop.UINT_GE) -def turn_to_vector(state, pack): +def turn_into_vector(state, pack): """ Turn a pack into a vector instruction """ # # TODO self.check_if_pack_supported(pack) @@ -546,7 +547,7 @@ i += 1 else: # note that heterogenous nodes are not yet tracked - vecop = expanded_map.get(arg, None) + vecop = state.find_expanded([arg]) if vecop: args[index] = vecop return vecop @@ -554,12 +555,20 @@ ops.append(vecop) if variables is not None: variables.append(vecop) - expanded_map[arg] = vecop + state.expand([arg], vecop) + #expanded_map.setdefault(arg,[]).append((vecop, -1)) #for i in range(vecop.count): # state.setvector_of_box(arg, i, vecop) args[index] = vecop return vecop + # quick search if it has already been expanded + expandargs = [op.getoperation().getarg(index) for op in pack.operations] + vecop = state.find_expanded(expandargs) + if vecop: + args[index] = vecop + return vecop + vecop = OpHelpers.create_vec(arg.type, left.bytesize, left.signed) ops.append(vecop) for i,node in enumerate(pack.operations): @@ -568,8 +577,8 @@ arguments = [vecop, arg, ConstInt(i), ConstInt(1)] vecop = OpHelpers.create_vec_pack(arg.type, arguments, left.bytesize, left.signed, vecop.count+1) - #state.setvector_of_box(arg, i, vecop) ops.append(vecop) + state.expand(expandargs, vecop) if variables is not None: variables.append(vecop) @@ -589,6 +598,44 @@ self.inputargs[arg] = None self.seen = {} + def expand(self, args, vecop): + index = 0 + if len(args) == 1: + # loop is executed once, thus sets -1 as index + index = -1 + for arg in args: + self.expanded_map.setdefault(arg, []).append((vecop, index)) + index += 1 + + def find_expanded(self, args): + if len(args) == 1: + candidates = self.expanded_map.get(args[0], []) + for (vecop, index) in candidates: + if index == -1: + # found an expanded variable/constant + return vecop + return None + possible = {} + for i, arg in enumerate(args): + expansions = self.expanded_map.get(arg, []) + candidates = [vecop for (vecop, index) in expansions \ + if i == index and possible.get(vecop,True)] + for vecop in candidates: + for key in possible.keys(): + if key not in candidates: + # delete every not possible key,value + possible[key] = False + # found a candidate, append it if not yet present + possible[vecop] = True + + if not possible: + # no possibility left, this combination is not expanded + return None + for vecop,valid in possible.items(): + if valid: + return vecop + return None + def post_schedule(self): loop = self.graph.loop self.ensure_args_unpacked(loop.jump) @@ -633,8 +680,8 @@ if node.pack: assert node.pack.numops() > 1 for node in node.pack.operations: - scheduler.mark_emitted(node, self) - turn_to_vector(self, node.pack) + scheduler.mark_emitted(node, self, unpack=False) + turn_into_vector(self, node.pack) return True return False @@ -673,7 +720,7 @@ fail_arguments[i] = arg def ensure_unpacked(self, index, arg): - if arg in self.seen or not arg.is_vector(): + if arg in self.seen or arg.is_vector(): return arg (pos, var) = self.getvector_of_box(arg) if var: @@ -722,7 +769,8 @@ if op.is_typecast(): if op.casts_down(): - return vec_reg_size // op.cast_from_bytesize() + size = op.cast_input_bytesize(vec_reg_size) + return size // op.cast_from_bytesize() else: return vec_reg_size // op.cast_to_bytesize() return vec_reg_size // op.bytesize @@ -791,10 +839,10 @@ if left.casts_down(): # size is reduced size = left.cast_input_bytesize(vec_reg_size) - import pdb; pdb.set_trace() return left.cast_from_bytesize() * self.numops() - size else: # size is increased + #size = left.cast_input_bytesize(vec_reg_size) return left.cast_to_bytesize() * self.numops() - vec_reg_size return left.bytesize * self.numops() - vec_reg_size @@ -823,10 +871,13 @@ In this step the pack is reduced in size to fit into an vector register. """ + before_count = len(packlist) + print "splitting pack", self pack = self while pack.pack_load(vec_reg_size) > Pack.FULL: pack.clear() oplist, newoplist = pack.slice_operations(vec_reg_size) + print " split of %dx, left: %d" % (len(oplist), len(newoplist)) pack.operations = oplist pack.update_pack_of_nodes() if not pack.leftmost().is_typecast(): @@ -842,6 +893,7 @@ newpack.clear() newpack.operations = [] break + print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -22,6 +22,11 @@ self.packs = packs self.vec_reg_size = 16 +class FakeVecScheduleState(VecScheduleState): + def __init__(self): + self.expanded_map = {} + + class SchedulerBaseTest(DependencyBaseTest): def setup_class(self): @@ -294,13 +299,11 @@ v15[2xi32] = vec_cast_float_to_int(v11[2xf64]) v16[2xi32] = vec_cast_float_to_int(v12[2xf64]) v17[2xi32] = vec_cast_float_to_int(v13[2xf64]) - v18[2xi16] = vec_int_signext(v14[2xi32],2) - v19[2xi16] = vec_int_signext(v15[2xi32],2) - v20[2xi16] = vec_int_signext(v16[2xi32],2) - v21[2xi16] = vec_int_signext(v17[2xi32],2) - v22[4xi16] = vec_pack_i(v18[2xi16], v19[2xi16], 2, 2) - v23[6xi16] = vec_pack_i(v22[4xi16], v20[2xi16], 4, 2) - v24[8xi16] = vec_pack_i(v23[6xi16], v21[2xi16], 6, 2) + v22[4xi32] = vec_pack_i(v14[2xi32], v15[2xi32], 2, 2) + v18[4xi16] = vec_int_signext(v22[4xi32],2) + v23[6xi16] = vec_pack_i(v16[2xi32], v17[2xi32], 2, 2) + v20[4xi16] = vec_int_signext(v23[4xi32],2) + v24[8xi16] = vec_pack_i(v18[4xi16], v20[4xi16], 4, 4) vec_raw_store(p1, i1, v24[8xi16], descr=short) """, False) self.assert_equal(loop2, loop3) @@ -463,3 +466,19 @@ packset.split_overloaded_packs() assert len(packset.packs) == 1 + def test_expand(self): + state = FakeVecScheduleState() + assert state.find_expanded([]) == None + state.expand(['a'], 'a') + assert state.find_expanded(['a']) == 'a' + state.expand(['a','b','c'], 'abc') + assert state.find_expanded(['a','b','c']) == 'abc' + state.expand(['a','d','c'], 'adc') + assert state.find_expanded(['a','b','c']) == 'abc' + assert state.find_expanded(['a','d','c']) == 'adc' + assert state.find_expanded(['d','d','c']) == None + state.expand(['d','d','c'], 'ddc') + assert state.find_expanded(['d','d','c']) == 'ddc' + + + diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -830,17 +830,19 @@ def split_overloaded_packs(self): newpacks = [] - import pdb; pdb.set_trace() for i,pack in enumerate(self.packs): load = pack.pack_load(self.vec_reg_size) if load > Pack.FULL: + print "overloaded pack", pack pack.split(newpacks, self.vec_reg_size) continue if load < Pack.FULL: + print "underloaded pack", pack for op in pack.operations: op.priority = -100 pack.clear() self.packs[i] = None continue + print "fully packed", pack self.packs = [pack for pack in self.packs + newpacks if pack] diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -456,7 +456,7 @@ def is_typecast(self): return False - def cast_count(self): + def cast_count(self, vec_reg_size): return self.casts[4] def cast_types(self): @@ -667,7 +667,7 @@ def cast_input_bytesize(self, vec_reg_size): count = vec_reg_size // self.cast_to_bytesize() - size = self.cast_from_bytesize() * self.count + size = self.cast_from_bytesize() * self.cast_count(vec_reg_size) return size class SignExtOp(object): @@ -689,8 +689,8 @@ arg = self.getarg(0) return arg.bytesize - def cast_count(self): - return self.casts[4] + def cast_input_bytesize(self, vec_reg_size): + return vec_reg_size # self.cast_from_bytesize() * self.cast_count(vec_reg_size) class VectorOp(object): @@ -1170,11 +1170,11 @@ ] _cast_ops = { - 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4), - 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8), - 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4), - 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8), - 'INT_SIGNEXT': ('i', 0, 'i', 0), + 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4, 2), + 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8, 2), + 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4, 2), + 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8, 2), + 'INT_SIGNEXT': ('i', 0, 'i', 0, 0), #'CAST_PTR_TO_INT': ('r', 0, 'i', 4), #'CAST_INT_TO_PTR': ('i', 4, 'r', 0), } From noreply at buildbot.pypy.org Wed Sep 16 14:46:11 2015 From: noreply at buildbot.pypy.org (vaibhavsood12) Date: Wed, 16 Sep 2015 14:46:11 +0200 (CEST) Subject: [pypy-commit] pypy py3.3_test_case_fixes: Fix test case for py3.3 branch Message-ID: <20150916124611.7D6251C0933@cobra.cs.uni-duesseldorf.de> Author: Vaibhav Sood Branch: py3.3_test_case_fixes Changeset: r79652:c5ef49e849b1 Date: 2015-08-24 15:09 +0530 http://bitbucket.org/pypy/pypy/changeset/c5ef49e849b1/ Log: Fix test case for py3.3 branch diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py --- a/pypy/interpreter/test/test_function.py +++ b/pypy/interpreter/test/test_function.py @@ -335,7 +335,7 @@ except TypeError as e: msg = str(e) msg = msg.replace('one', '1') # CPython puts 'one', PyPy '1' - assert "len() takes exactly 1 argument (0 given)" in msg + assert "len() missing 1 required positional argument: 'obj'" in msg else: assert 0, "did not raise" @@ -344,7 +344,7 @@ except TypeError as e: msg = str(e) msg = msg.replace('one', '1') # CPython puts 'one', PyPy '1' - assert "len() takes exactly 1 argument (2 given)" in msg + assert "len() takes 1 positional argument but 2 were given" in msg else: assert 0, "did not raise" From noreply at buildbot.pypy.org Wed Sep 16 14:46:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 16 Sep 2015 14:46:13 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Merged in vaibhavsood12/pypy/py3.3_test_case_fixes (pull request #331) Message-ID: <20150916124613.E57E21C0933@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: py3.3 Changeset: r79653:9cfeff70794d Date: 2015-09-16 14:46 +0200 http://bitbucket.org/pypy/pypy/changeset/9cfeff70794d/ Log: Merged in vaibhavsood12/pypy/py3.3_test_case_fixes (pull request #331) Fix test case for py3.3 branch diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py --- a/pypy/interpreter/test/test_function.py +++ b/pypy/interpreter/test/test_function.py @@ -335,7 +335,7 @@ except TypeError as e: msg = str(e) msg = msg.replace('one', '1') # CPython puts 'one', PyPy '1' - assert "len() takes exactly 1 argument (0 given)" in msg + assert "len() missing 1 required positional argument: 'obj'" in msg else: assert 0, "did not raise" @@ -344,7 +344,7 @@ except TypeError as e: msg = str(e) msg = msg.replace('one', '1') # CPython puts 'one', PyPy '1' - assert "len() takes exactly 1 argument (2 given)" in msg + assert "len() takes 1 positional argument but 2 were given" in msg else: assert 0, "did not raise" From noreply at buildbot.pypy.org Wed Sep 16 15:43:24 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 15:43:24 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: import stmgc with noconflict objects Message-ID: <20150916134324.CEEC91C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79654:296077e0562c Date: 2015-09-16 10:55 +0200 http://bitbucket.org/pypy/pypy/changeset/296077e0562c/ Log: import stmgc with noconflict objects diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -7d754bc0f3a7 +6ca47dad66a6 diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c --- a/rpython/translator/stm/src_stm/stm/core.c +++ b/rpython/translator/stm/src_stm/stm/core.c @@ -12,7 +12,7 @@ { assert(undo->type != TYPE_POSITION_MARKER); free(undo->backup); - assert(undo->backup = (char*)-88); + assert(undo->backup = (char*)0xbb); increment_total_allocated(-SLICE_SIZE(undo->slice)); } @@ -308,7 +308,7 @@ } } -static void reset_modified_from_backup_copies(int segment_num); /* forward */ +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj); /* forward */ static bool _stm_validate(void) { @@ -409,6 +409,25 @@ if (LIKELY(!_stm_was_read(obj))) continue; + /* check for NO_CONFLICT flag in seg0. While its data may + not be current there, the flag will be there and is + immutable. (we cannot check in my_segnum bc. we may + only have executed stm_read(o) but not touched its pages + yet -> they may be NO_ACCESS */ + struct object_s *obj0 = (struct object_s *)REAL_ADDRESS(get_segment_base(0), obj); + if (obj0->stm_flags & GCFLAG_NO_CONFLICT) { + /* obj is noconflict and therefore shouldn't cause + an abort. However, from now on, we also assume + that an abort would not roll-back to what is in + the backup copy, as we don't trace the bkcpy + during major GCs. + We choose the approach to reset all our changes + to this obj here, so that we can throw away the + backup copy completely: */ + reset_modified_from_backup_copies(my_segnum, obj); + continue; + } + /* conflict! */ dprintf(("_stm_validate() failed for obj %p\n", obj)); @@ -418,7 +437,7 @@ from the old (but unmodified) version to the newer version. */ - reset_modified_from_backup_copies(my_segnum); + reset_modified_from_backup_copies(my_segnum, NULL); timing_write_read_contention(cl->written, undo); needs_abort = true; break; @@ -1399,7 +1418,7 @@ invoke_general_finalizers(tl); } -static void reset_modified_from_backup_copies(int segment_num) +static void reset_modified_from_backup_copies(int segment_num, object_t *only_obj) { #pragma push_macro("STM_PSEGMENT") #pragma push_macro("STM_SEGMENT") @@ -1415,7 +1434,11 @@ for (; undo < end; undo++) { if (undo->type == TYPE_POSITION_MARKER) continue; + object_t *obj = undo->object; + if (only_obj != NULL && obj != only_obj) + continue; + char *dst = REAL_ADDRESS(pseg->pub.segment_base, obj); memcpy(dst + SLICE_OFFSET(undo->slice), @@ -1427,12 +1450,29 @@ SLICE_SIZE(undo->slice), undo->backup)); free_bk(undo); + + if (only_obj != NULL) { + assert(IMPLY(only_obj != NULL, + (((struct object_s *)dst)->stm_flags + & (GCFLAG_NO_CONFLICT + | GCFLAG_WRITE_BARRIER + | GCFLAG_WB_EXECUTED)) + == (GCFLAG_NO_CONFLICT | GCFLAG_WRITE_BARRIER))); + /* copy last element over this one */ + end--; + list->count -= 3; + if (undo < end) + *undo = *end; + undo--; /* next itr */ + } } - /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ - check_all_write_barrier_flags(pseg->pub.segment_base, list); + if (only_obj == NULL) { + /* check that all objects have the GCFLAG_WRITE_BARRIER afterwards */ + check_all_write_barrier_flags(pseg->pub.segment_base, list); - list_clear(list); + list_clear(list); + } #pragma pop_macro("STM_SEGMENT") #pragma pop_macro("STM_PSEGMENT") } @@ -1468,7 +1508,7 @@ }); acquire_modification_lock_wr(segment_num); - reset_modified_from_backup_copies(segment_num); + reset_modified_from_backup_copies(segment_num, NULL); release_modification_lock_wr(segment_num); _verify_cards_cleared_in_all_lists(pseg); diff --git a/rpython/translator/stm/src_stm/stm/core.h b/rpython/translator/stm/src_stm/stm/core.h --- a/rpython/translator/stm/src_stm/stm/core.h +++ b/rpython/translator/stm/src_stm/stm/core.h @@ -43,6 +43,7 @@ GCFLAG_CARDS_SET = _STM_GCFLAG_CARDS_SET, GCFLAG_VISITED = 0x10, GCFLAG_FINALIZATION_ORDERING = 0x20, + GCFLAG_NO_CONFLICT = _STM_GCFLAG_NO_CONFLICT, /* All remaining bits of the 32-bit 'stm_flags' field are taken by the "overflow number". This is a number that identifies the "overflow objects" from the current transaction among all old @@ -50,7 +51,7 @@ current transaction that have been flushed out of the nursery, which occurs if the same transaction allocates too many objects. */ - GCFLAG_OVERFLOW_NUMBER_bit0 = 0x40 /* must be last */ + GCFLAG_OVERFLOW_NUMBER_bit0 = 0x80 /* must be last */ }; #define SYNC_QUEUE_SIZE 31 diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h --- a/rpython/translator/stm/src_stm/stmgc.h +++ b/rpython/translator/stm/src_stm/stmgc.h @@ -162,6 +162,7 @@ #endif #define _STM_GCFLAG_WRITE_BARRIER 0x01 +#define _STM_GCFLAG_NO_CONFLICT 0x40 #define _STM_FAST_ALLOC (66*1024) #define _STM_NSE_SIGNAL_ABORT 1 #define _STM_NSE_SIGNAL_MAX 2 @@ -780,6 +781,24 @@ void stm_queue_tracefn(stm_queue_t *queue, void trace(object_t **)); + +/* stm_allocate_noconflict() allocates a special kind of object. Validation + will never detect conflicts on such an object. However, writes to it can + get lost. More precisely: every possible point for validation during a + transaction may import a committed version of such objs, thereby resetting + it or even contain not-yet-seen values from other (committed) transactions. + Hence, changes to such an obj that a transaction commits may or may not + propagate to other transactions. */ +__attribute__((always_inline)) +static inline object_t *stm_allocate_noconflict(ssize_t size_rounded_up) +{ + object_t *o = stm_allocate(size_rounded_up); + o->stm_flags |= _STM_GCFLAG_NO_CONFLICT; + return o; +} + + + /* ==================== END ==================== */ extern void (*stmcb_expand_marker)(char *segment_base, uintptr_t odd_number, From noreply at buildbot.pypy.org Wed Sep 16 15:43:26 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 15:43:26 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: add rstm.allocate_noconflict() Message-ID: <20150916134326.F0DA31C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79655:c657942f1620 Date: 2015-09-16 11:26 +0200 http://bitbucket.org/pypy/pypy/changeset/c657942f1620/ Log: add rstm.allocate_noconflict() diff --git a/rpython/memory/gctransform/stmframework.py b/rpython/memory/gctransform/stmframework.py --- a/rpython/memory/gctransform/stmframework.py +++ b/rpython/memory/gctransform/stmframework.py @@ -234,6 +234,7 @@ gct_stm_queue_get = _gct_with_roots_pushed gct_stm_queue_put = _gct_with_roots_pushed gct_stm_queue_join = _gct_with_roots_pushed + gct_stm_allocate_preexisting = _gct_with_roots_pushed def gct_stm_malloc_nonmovable(self, hop): @@ -253,6 +254,26 @@ self.pop_roots(hop, livevars) hop.genop("cast_opaque_ptr", [v_result], resultvar=op.result) + def gct_stm_malloc_noconflict(self, hop): + op = hop.spaceop + PTRTYPE = op.result.concretetype + TYPE = PTRTYPE.TO + type_id = self.get_type_id(TYPE) + + c_type_id = rmodel.inputconst(TYPE_ID, type_id) + info = self.layoutbuilder.get_info(type_id) + c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) + + livevars = self.push_roots(hop) + v_result = hop.genop("stm_allocate_noconflict", + [c_size, c_type_id], + resulttype=llmemory.GCREF) + self.pop_roots(hop, livevars) + hop.genop("cast_opaque_ptr", [v_result], resultvar=op.result) + + + + diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -190,6 +190,13 @@ return llop.stm_allocate_preexisting(TP, size, p) @specialize.ll() +def allocate_noconflict(GCTYPE): + """Return a new instance of GCTYPE that never generates conflicts when + reading or writing to it. However, modifications may get lost + and are not guaranteed to propagate.""" + return llop.stm_malloc_noconflict(lltype.Ptr(GCTYPE)) + + at specialize.ll() def allocate_nonmovable(GCTYPE): return llop.stm_malloc_nonmovable(lltype.Ptr(GCTYPE)) diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -992,6 +992,7 @@ op_stm_allocate_finalizer = _stm_not_implemented op_stm_allocate_nonmovable = _stm_not_implemented op_stm_allocate_preexisting = _stm_not_implemented + op_stm_malloc_noconflict = _stm_not_implemented op_stm_malloc_nonmovable = _stm_not_implemented op_stm_can_move = _stm_not_implemented op_stm_read = _stm_not_implemented 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 @@ -423,6 +423,8 @@ 'stm_allocate_finalizer': LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_f_light': LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_preexisting':LLOp(sideeffects=False, canmallocgc=True), + 'stm_allocate_noconflict':LLOp(sideeffects=False, canmallocgc=True), + 'stm_malloc_noconflict': LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_nonmovable':LLOp(sideeffects=False, canmallocgc=True), 'stm_malloc_nonmovable': LLOp(sideeffects=False, canmallocgc=True), 'stm_set_into_obj': LLOp(), diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py --- a/rpython/translator/stm/funcgen.py +++ b/rpython/translator/stm/funcgen.py @@ -129,6 +129,17 @@ (result, arg_size, arg_size) + '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id)) +def stm_allocate_noconflict(funcgen, op): + arg_size = funcgen.expr(op.args[0]) # <- could be smaller than 16 here + arg_type_id = funcgen.expr(op.args[1]) + result = funcgen.expr(op.result) + # XXX NULL returns? + return ('%s = (rpygcchar_t *)stm_allocate_noconflict(%s >= 16 ? %s : 16); ' % + (result, arg_size, arg_size) + + 'pypy_stm_memclearinit((object_t*)%s, 0, %s >= 16 ? %s : 16);' % + (result, arg_size, arg_size) + + '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id)) + def stm_set_into_obj(funcgen, op): assert op.args[0].concretetype == llmemory.GCREF arg_obj = funcgen.expr(op.args[0]) diff --git a/rpython/translator/stm/readbarrier.py b/rpython/translator/stm/readbarrier.py --- a/rpython/translator/stm/readbarrier.py +++ b/rpython/translator/stm/readbarrier.py @@ -7,6 +7,7 @@ MALLOCS = set([ 'malloc', 'malloc_varsize', 'malloc_nonmovable', 'malloc_nonmovable_varsize', + 'malloc_noconflict', 'malloc_noconflict_varsize', ]) READ_OPS = set(['getfield', 'getarrayitem', 'getinteriorfield', 'raw_load']) diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py --- a/rpython/translator/stm/test/test_ztranslated.py +++ b/rpython/translator/stm/test/test_ztranslated.py @@ -592,7 +592,6 @@ assert count == 1 assert intmask(array[0].index) == -1234 assert cast_gcref_to_instance(X, array[0].object) is x1 - h.freelist(array) # print "ok!" return 0 @@ -709,3 +708,18 @@ t, cbuilder = self.compile(main) data = cbuilder.cmdexec('') assert 'ok!\n' in data + + def test_allocate_noconflict(self): + S = lltype.GcStruct('S', ('n', lltype.Signed)) + + def main(argv): + s1 = rstm.allocate_noconflict(S) + s1.n = 42 + assert s1.n == 42 + # + print "ok!" + return 0 + + t, cbuilder = self.compile(main) + data = cbuilder.cmdexec('') + assert 'ok!\n' in data From noreply at buildbot.pypy.org Wed Sep 16 15:43:29 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 15:43:29 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: add varsize variant Message-ID: <20150916134329.29BC01C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79656:4fac55ea7358 Date: 2015-09-16 13:48 +0200 http://bitbucket.org/pypy/pypy/changeset/4fac55ea7358/ Log: add varsize variant diff --git a/rpython/memory/gctransform/stmframework.py b/rpython/memory/gctransform/stmframework.py --- a/rpython/memory/gctransform/stmframework.py +++ b/rpython/memory/gctransform/stmframework.py @@ -271,6 +271,32 @@ self.pop_roots(hop, livevars) hop.genop("cast_opaque_ptr", [v_result], resultvar=op.result) + def gct_stm_malloc_noconflict_varsize(self, hop): + op = hop.spaceop + args = hop.inputargs() + PTRTYPE = op.result.concretetype + TYPE = PTRTYPE.TO + type_id = self.get_type_id(TYPE) + info = self.layoutbuilder.get_info(type_id) + info_varsize = self.layoutbuilder.get_info_varsize(type_id) + + v_length = args[0] + c_type_id = rmodel.inputconst(TYPE_ID, type_id) + c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) + c_ofstolength = rmodel.inputconst(lltype.Signed, + info_varsize.ofstolength) + c_varitemsize = rmodel.inputconst(lltype.Signed, + info_varsize.varitemsize) + + args = [c_size, c_varitemsize, c_ofstolength, v_length, c_type_id] + + livevars = self.push_roots(hop) + v_result = hop.genop("stm_allocate_noconflict_varsize", + args, resulttype=llmemory.GCREF) + self.pop_roots(hop, livevars) + hop.genop("cast_opaque_ptr", [v_result], resultvar=op.result) + hop.genop("stm_set_into_obj", [v_result, c_ofstolength, v_length]) + diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -190,11 +190,14 @@ return llop.stm_allocate_preexisting(TP, size, p) @specialize.ll() -def allocate_noconflict(GCTYPE): +def allocate_noconflict(GCTYPE, n=None): """Return a new instance of GCTYPE that never generates conflicts when reading or writing to it. However, modifications may get lost and are not guaranteed to propagate.""" - return llop.stm_malloc_noconflict(lltype.Ptr(GCTYPE)) + if n is None: + return llop.stm_malloc_noconflict(lltype.Ptr(GCTYPE)) + else: + return llop.stm_malloc_noconflict_varsize(lltype.Ptr(GCTYPE), n) @specialize.ll() def allocate_nonmovable(GCTYPE): 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 @@ -424,7 +424,9 @@ 'stm_allocate_f_light': LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_preexisting':LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_noconflict':LLOp(sideeffects=False, canmallocgc=True), + 'stm_allocate_noconflict_varsize':LLOp(sideeffects=False, canmallocgc=True), 'stm_malloc_noconflict': LLOp(sideeffects=False, canmallocgc=True), + 'stm_malloc_noconflict_varsize': LLOp(sideeffects=False, canmallocgc=True), 'stm_allocate_nonmovable':LLOp(sideeffects=False, canmallocgc=True), 'stm_malloc_nonmovable': LLOp(sideeffects=False, canmallocgc=True), 'stm_set_into_obj': LLOp(), diff --git a/rpython/translator/stm/funcgen.py b/rpython/translator/stm/funcgen.py --- a/rpython/translator/stm/funcgen.py +++ b/rpython/translator/stm/funcgen.py @@ -123,9 +123,9 @@ arg_type_id = funcgen.expr(op.args[1]) result = funcgen.expr(op.result) # XXX NULL returns? - return ('%s = (rpygcchar_t *)_stm_allocate_external(%s >= 16 ? %s : 16); ' % + return ('%s = (rpygcchar_t *)_stm_allocate_external(%s >= 16 ? %s : 16);\n' % (result, arg_size, arg_size) + - 'pypy_stm_memclearinit((object_t*)%s, 0, %s >= 16 ? %s : 16);' % + 'pypy_stm_memclearinit((object_t*)%s, 0, %s >= 16 ? %s : 16);\n' % (result, arg_size, arg_size) + '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id)) @@ -134,12 +134,33 @@ arg_type_id = funcgen.expr(op.args[1]) result = funcgen.expr(op.result) # XXX NULL returns? - return ('%s = (rpygcchar_t *)stm_allocate_noconflict(%s >= 16 ? %s : 16); ' % + return ('%s = (rpygcchar_t *)stm_allocate_noconflict(%s >= 16 ? %s : 16);\n' % (result, arg_size, arg_size) + - 'pypy_stm_memclearinit((object_t*)%s, 0, %s >= 16 ? %s : 16);' % + 'pypy_stm_memclearinit((object_t*)%s, 0, %s >= 16 ? %s : 16);\n' % (result, arg_size, arg_size) + '((rpyobj_t *)%s)->tid = %s;' % (result, arg_type_id)) +def stm_allocate_noconflict_varsize(funcgen, op): + arg_size = funcgen.expr(op.args[0]) + arg_itemsize = funcgen.expr(op.args[1]) + arg_ofstolength = funcgen.expr(op.args[2]) + arg_length = funcgen.expr(op.args[3]) + arg_type_id = funcgen.expr(op.args[4]) + result = funcgen.expr(op.result) + # XXX NULL returns? + return """ +{ + ssize_t size = %s + %s * %s; + %s = (rpygcchar_t *)stm_allocate_noconflict(size); + pypy_stm_memclearinit((object_t*)%s, %s, size); + ((rpyobj_t *)%s)->tid = %s; +} + """ % (arg_size, arg_itemsize, arg_length, + result, + result, arg_size, + result, arg_type_id,) + + def stm_set_into_obj(funcgen, op): assert op.args[0].concretetype == llmemory.GCREF arg_obj = funcgen.expr(op.args[0]) diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py --- a/rpython/translator/stm/test/test_ztranslated.py +++ b/rpython/translator/stm/test/test_ztranslated.py @@ -723,3 +723,18 @@ t, cbuilder = self.compile(main) data = cbuilder.cmdexec('') assert 'ok!\n' in data + + def test_allocate_noconflict2(self): + S = lltype.GcArray(lltype.Signed) + + def main(argv): + s1 = rstm.allocate_noconflict(S, 4) + s1[1] = 42 + assert s1[1] == 42 + # + print "ok!" + return 0 + + t, cbuilder = self.compile(main) + data = cbuilder.cmdexec('') + assert 'ok!\n' in data From noreply at buildbot.pypy.org Wed Sep 16 15:43:31 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 16 Sep 2015 15:43:31 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: wip: making mapdict_cache a noconflict object Message-ID: <20150916134331.635191C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79657:12865f558081 Date: 2015-09-16 15:43 +0200 http://bitbucket.org/pypy/pypy/changeset/12865f558081/ Log: wip: making mapdict_cache a noconflict object diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -9,7 +9,7 @@ BaseValueIterator, BaseItemIterator, _never_equal_to_string ) from pypy.objspace.std.typeobject import MutableCell - +from rpython.rlib.objectmodel import we_are_translated # ____________________________________________________________ # attribute shapes @@ -843,16 +843,32 @@ INVALID_CACHE_ENTRY.map_wref = weakref.ref(_invalid_cache_entry_map) # different from any real map ^^^ +from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper import annlowlevel +MAPDICT_CACHE = lltype.GcArray(llmemory.GCREF) +PMAPDICT_CACHE = lltype.Ptr(MAPDICT_CACHE) +NULL_MAPDICTCACHE = lltype.nullptr(MAPDICT_CACHE) + + def init_mapdict_cache(pycode): num_entries = len(pycode.co_names_w) - pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries + # pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries + if pycode.space.config.translation.stm: + from rpython.rlib.rstm import allocate_noconflict + pycode._mapdict_caches = allocate_noconflict(MAPDICT_CACHE, num_entries) + else: + pycode._mapdict_caches = lltype.malloc(MAPDICT_CACHE, num_entries) + # + for i in range(num_entries): + pycode._mapdict_caches[i] = annlowlevel.cast_instance_to_gcref(INVALID_CACHE_ENTRY) + @jit.dont_look_inside def _fill_cache(pycode, nameindex, map, version_tag, storageindex, w_method=None): - entry = pycode._mapdict_caches[nameindex] + entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) if entry is INVALID_CACHE_ENTRY: entry = CacheEntry() - pycode._mapdict_caches[nameindex] = entry + pycode._mapdict_caches[nameindex] = annlowlevel.cast_instance_to_gcref(entry) entry.map_wref = weakref.ref(map) entry.version_tag = version_tag entry.storageindex = storageindex @@ -863,7 +879,7 @@ def LOAD_ATTR_caching(pycode, w_obj, nameindex): # this whole mess is to make the interpreter quite a bit faster; it's not # used if we_are_jitted(). - entry = pycode._mapdict_caches[nameindex] + entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) map = w_obj._get_mapdict_map() if entry.is_valid_for_map(map) and entry.w_method is None: # everything matches, it's incredibly fast @@ -920,7 +936,7 @@ def LOOKUP_METHOD_mapdict(f, nameindex, w_obj): pycode = f.getcode() - entry = pycode._mapdict_caches[nameindex] + entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) if entry.is_valid_for_obj(w_obj): w_method = entry.w_method if w_method is not None: diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -719,7 +719,7 @@ def check(space, w_func, name): w_code = space.getattr(w_func, space.wrap('func_code')) nameindex = map(space.str_w, w_code.co_names_w).index(name) - entry = w_code._mapdict_caches[nameindex] + entry = annlowlevel.cast_gcref_to_instance(CacheEntry, w_code._mapdict_caches[nameindex]) entry.failure_counter = 0 entry.success_counter = 0 INVALID_CACHE_ENTRY.failure_counter = 0 @@ -727,7 +727,7 @@ w_res = space.call_function(w_func) assert space.eq_w(w_res, space.wrap(42)) # - entry = w_code._mapdict_caches[nameindex] + entry = annlowlevel.cast_gcref_to_instance(CacheEntry, w_code._mapdict_caches[nameindex]) if entry is INVALID_CACHE_ENTRY: failures = successes = 0 else: diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -189,11 +189,15 @@ size = llmemory.sizeof(TP.TO) return llop.stm_allocate_preexisting(TP, size, p) + at dont_look_inside @specialize.ll() def allocate_noconflict(GCTYPE, n=None): """Return a new instance of GCTYPE that never generates conflicts when reading or writing to it. However, modifications may get lost and are not guaranteed to propagate.""" + if not we_are_translated(): # for tests + return lltype.malloc(GCTYPE, n=n) + # if n is None: return llop.stm_malloc_noconflict(lltype.Ptr(GCTYPE)) else: From noreply at buildbot.pypy.org Wed Sep 16 18:06:59 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 16 Sep 2015 18:06:59 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: forcing memo of variables while parsing to the same memo at runtime (only jitviewer and the test suite affected) Message-ID: <20150916160659.C9EEA1C1E40@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79658:fe1eb22de735 Date: 2015-09-16 18:06 +0200 http://bitbucket.org/pypy/pypy/changeset/fe1eb22de735/ Log: forcing memo of variables while parsing to the same memo at runtime (only jitviewer and the test suite affected) poking costmodel tests, accumulator in the algorthim missing diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -356,7 +356,7 @@ pack = '' if self.pack: pack = "p: %d" % self.pack.numops() - return "Node(%s,%s i: %d)" % (self.op.getopname(), pack, self.opidx) + return "Node(%s,%s i: %d)" % (self.op, pack, self.opidx) def __ne__(self, other): return not self.__eq__(other) diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -7,6 +7,7 @@ from rpython.jit.metainterp.optimizeopt.renamer import Renamer from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.jitexc import NotAProfitableLoop +from rpython.rlib.objectmodel import specialize class SchedulerState(object): @@ -78,7 +79,7 @@ state.renamer.rename(op) if unpack: state.ensure_args_unpacked(op) - node.position = len(state.oplist) + node.vector=Trueposition = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY to = dep.to @@ -131,115 +132,6 @@ for node in state.graph.nodes: assert node.emitted -#UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, -# rop.UINT_LT, rop.UINT_LE, -# rop.UINT_GT, rop.UINT_GE) - -#class Type(object): -# """ The type of one operation. Saves type, size and sign. """ -# @staticmethod -# def of(op): -# descr = op.getdescr() -# if descr: -# type = INT -# if descr.is_array_of_floats() or descr.concrete_type == FLOAT: -# type = FLOAT -# size = descr.get_item_size_in_bytes() -# sign = descr.is_item_signed() -# return Type(type, size, sign) -# else: -# size = 8 -# sign = True -# if op.type == 'f' or op.getopnum() in UNSIGNED_OPS: -# sign = False -# return Type(op.type, size, sign) -# -# def __init__(self, type, size, signed): -# assert type in (FLOAT, INT) -# self.type = type -# self.size = size -# self.signed = signed -# -# def bytecount(self): -# return self.size -# -# def clone(self): -# return Type(self.type, self.size, self.signed) -# -# def __repr__(self): -# sign = '-' -# if not self.signed: -# sign = '+' -# return 'Type(%s%s, %d)' % (sign, self.type, self.size) -# - #UNKNOWN_TYPE = '-' - - #@staticmethod - #def of(box, count=-1): - # assert box.type == 'V' - # if count == -1: - # count = box.getcount() - # return Type(box.gettype(), box.getsize(), box.getsigned(), count) - - #@staticmethod - #def by_descr(descr, vec_reg_size): - # _t = INT - # signed = descr.is_item_signed() - # if descr.is_array_of_floats() or descr.concrete_type == FLOAT: - # _t = FLOAT - # signed = False - # size = descr.get_item_size_in_bytes() - # pt = Type(_t, size, signed, vec_reg_size // size) - # return pt - - #def clone(self): - # return Type(self.type, self.size, self.signed, self.count) - - #def new_vector_box(self, count = -1): - # if count == -1: - # count = self.count - # assert count > 1 - # assert self.type in ('i','f') - # assert self.size > 0 - # xxx - # return BoxVector(self.type, count, self.size, self.signed) - - #def combine(self, other): - # """ nothing to be done here """ - # if not we_are_translated(): - # assert self.type == other.type - # assert self.signed == other.signed - - - #def byte_size(self): - # return self.count * self.size - - #def setsize(self, size): - # self.size = size - - #def setcount(self, count): - # self.count = count - - #def gettype(self): - # return self.type - - #def getsize(self): - # return self.size - - #def getcount(self): - # return self.count - - - -class TypeOutput(object): - def __init__(self, type, count): - self.type = type - self.count = count - - - def bytecount(self): - return self.count * self.type.bytecount() - class TypeRestrict(object): ANY_TYPE = -1 ANY_SIZE = -1 @@ -273,13 +165,6 @@ TR_LONG = TypeRestrict(INT, 8, 2) TR_INT_2 = TypeRestrict(INT, 4, 2) - #INT = OpToVectorOp((TR_ANY_INTEGER, TR_ANY_INTEGER), DT_PASS) - #FLOAT = OpToVectorOp((TR_ANY_FLOAT, TR_ANY_FLOAT), DT_PASS) - #FLOAT_UNARY = OpToVectorOp((TR_ANY_FLOAT,), DT_PASS) - #LOAD = LoadToVectorLoad() - #STORE = StoreToVectorStore() - #GUARD = PassThroughOp((TR_ANY_INTEGER,)) - # note that the following definition is x86 arch specific MAPPING = { rop.VEC_INT_ADD: [TR_ANY_INTEGER, TR_ANY_INTEGER], @@ -318,11 +203,6 @@ rop.VEC_INT_IS_TRUE: [TR_ANY_INTEGER,TR_ANY_INTEGER], } - # TODO? - UNSIGNED_OPS = (rop.UINT_FLOORDIV, rop.UINT_RSHIFT, - rop.UINT_LT, rop.UINT_LE, - rop.UINT_GT, rop.UINT_GE) - def turn_into_vector(state, pack): """ Turn a pack into a vector instruction """ # @@ -412,39 +292,6 @@ # self.input_type.getsize() != vecop.getsize(): # vecop = self.extend(vecop, self.input_type) - # use the input as an indicator for the pack type - #packable = vecop.maximum_numops() - #packed = vecop.count - #assert packed >= 0 - #assert packable >= 0 - #if packed > packable: - # # the argument has more items than the operation is able to process! - # # pos == 0 then it is already at the right place - # if pos != 0: - # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) - # state.remember_args_in_vector(i, args[i]) - # #self.update_input_output(self.pack) - # continue - # else: - # assert vecop is not None - # args[i] = vecop - # continue - #vboxes = self.vector_boxes_for_args(i) - #if packed < packable and len(vboxes) > 1: - # # the argument is scattered along different vector boxes - # args[i] = self.gather(vboxes, packable) - # state.remember_args_in_vector(i, args[i]) - # continue - #if pos != 0: - # # The vector box is at a position != 0 but it - # # is required to be at position 0. Unpack it! - # args[i] = self.unpack(vecop, pos, packed - pos, self.input_type) - # state.remember_args_in_vector(i, args[i]) - # continue - ## - #assert vecop is not None - #args[i] = vecop - def check_if_pack_supported(self, pack): op0 = pack.operations[0].getoperation() if self.input_type is None: @@ -461,25 +308,6 @@ # see assembler for comment why raise NotAProfitableLoop -def extend(self, vbox, newtype): - assert vbox.gettype() == newtype.gettype() - if vbox.gettype() == INT: - return self.extend_int(vbox, newtype) - else: - raise NotImplementedError("cannot yet extend float") - -def extend_int(self, vbox, newtype): - vbox_cloned = newtype.new_vector_box(vbox.getcount()) - self.sched_data._prevent_signext(newtype.getsize(), vbox.getsize()) - newsize = newtype.getsize() - assert newsize > 0 - op = ResOperation(rop.VEC_INT_SIGNEXT, - [vbox, ConstInt(newsize)], - vbox_cloned) - self.costmodel.record_cast_int(vbox.getsize(), newtype.getsize(), vbox.getcount()) - self.vecops.append(op) - return vbox_cloned - def unpack_from_vector(state, arg, index, count): """ Extract parts of the vector box into another vector box """ print "unpack i", index, "c", count, "v", arg @@ -556,9 +384,6 @@ if variables is not None: variables.append(vecop) state.expand([arg], vecop) - #expanded_map.setdefault(arg,[]).append((vecop, -1)) - #for i in range(vecop.count): - # state.setvector_of_box(arg, i, vecop) args[index] = vecop return vecop @@ -642,7 +467,7 @@ SchedulerState.post_schedule(self) # add accumulation info to the descriptor - #for version in self.loop.versions: + # TODO for version in self.loop.versions: # # this needs to be done for renamed (accum arguments) # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] #self.appended_arg_count = len(sched_data.invariant_vector_vars) @@ -717,7 +542,7 @@ if argument and not argument.is_constant(): arg = self.ensure_unpacked(i, argument) if argument is not arg: - fail_arguments[i] = arg + fail_args[i] = arg def ensure_unpacked(self, index, arg): if arg in self.seen or arg.is_vector(): @@ -756,9 +581,8 @@ break self.setvector_of_box(arg, i, box) - def opcount_filling_vector_register(pack, vec_reg_size): - """ how many operations of that kind can one execute + """ How many operations of that kind can one execute with a machine instruction of register size X? """ op = pack.leftmost() @@ -790,10 +614,16 @@ def numops(self): return len(self.operations) - def leftmost(self): + @specialize.arg(1) + def leftmost(self, node=False): + if node: + return self.operations[0] return self.operations[0].getoperation() - def rightmost(self): + @specialize.arg(1) + def rightmost(self, node=False): + if node: + return self.operations[-1] return self.operations[-1].getoperation() def pack_type(self): @@ -933,7 +763,7 @@ def __repr__(self): if len(self.operations) == 0: return "Pack(empty)" - return "Pack(%dx %s)" % (self.numops(), self.operations[0]) + return "Pack(%dx %s)" % (self.numops(), self.operations) def is_accumulating(self): return self.accum is not None @@ -943,14 +773,11 @@ cloned.accum = self.accum return cloned - class Pair(Pack): """ A special Pack object with only two statements. """ def __init__(self, left, right): assert isinstance(left, Node) assert isinstance(right, Node) - self.left = left - self.right = right Pack.__init__(self, [left, right]) def __eq__(self, other): @@ -960,246 +787,28 @@ class AccumPair(Pair): """ A pair that keeps track of an accumulation value """ - def __init__(self, left, right, input_type, output_type, accum): + def __init__(self, left, right, accum): assert isinstance(left, Node) assert isinstance(right, Node) - Pair.__init__(self, left, right, input_type, output_type) - self.left = left - self.right = right + Pair.__init__(self, left, right) self.accum = accum -#class OpToVectorOp(object): -# def __init__(self): #, restrictargs, typeoutput): -# pass -# #self.args = list(restrictargs) # do not use a tuple. rpython cannot union -# #self.out = typeoutput +#def extend(self, vbox, newtype): +# assert vbox.gettype() == newtype.gettype() +# if vbox.gettype() == INT: +# return self.extend_int(vbox, newtype) +# else: +# raise NotImplementedError("cannot yet extend float") # -#class OpToVectorOpConv(OpToVectorOp): -# def __init__(self, intype, outtype): -# #self.from_size = intype.getsize() -# #self.to_size = outtype.getsize() -# #OpToVectorOp.__init__(self, (intype, ), outtype) -# pass -# -# def new_result_vector_box(self): -# type = self.output_type.gettype() -# size = self.to_size -# count = self.output_type.getcount() -# vec_reg_size = self.sched_data.vec_reg_size -# if count * size > vec_reg_size: -# count = vec_reg_size // size -# signed = self.output_type.signed -# assert type in ('i','f') -# assert size > 0 -# assert count > 1 -# return BoxVector(type, count, size, signed) -# -# def get_output_type_given(self, input_type, op): -# return self.result_ptype -# -# def get_input_type_given(self, output_type, op): -# return self.arg_ptypes[0] -# -# def force_input(self, ptype): -# return self.arg_ptypes[0] -# -#class SignExtToVectorOp(OpToVectorOp): -# def __init__(self, intype, outtype): -# OpToVectorOp.__init__(self, intype, outtype) -# self.size = -1 -# -# def before_argument_transform(self, args): -# sizearg = args[1] -# assert isinstance(sizearg, ConstInt) -# self.size = sizearg.value -# -# def new_result_vector_box(self): -# type = self.output_type.gettype() -# count = self.input_type.getcount() -# vec_reg_size = self.sched_data.vec_reg_size -# if count * self.size > vec_reg_size: -# count = vec_reg_size // self.size -# signed = self.input_type.signed -# assert type in ('i','f') -# assert self.size > 0 -# assert count > 1 -# return BoxVector(type, count, self.size, signed) -# -# def get_output_type_given(self, input_type, op): -# sizearg = op.getarg(1) -# assert isinstance(sizearg, ConstInt) -# output_type = input_type.clone() -# output_type.setsize(sizearg.value) -# return output_type -# -# def get_input_type_given(self, output_type, op): -# raise AssertionError("can never infer input type!") -# -#class LoadToVectorLoad(OpToVectorOp): -# def __init__(self): -# OpToVectorOp.__init__(self, (), TypeRestrict()) -# -# # OLD def before_argument_transform(self, args): -# #count = min(self.output_type.getcount(), len(self.getoperations())) -# #args.append(ConstInt(count)) -# -# def get_output_type_given(self, input_type, op): -# return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) -# -# def get_input_type_given(self, output_type, op): -# return None -# -#class StoreToVectorStore(OpToVectorOp): -# """ Storing operations are special because they are not allowed -# to store to memory if the vector is not fully filled. -# Thus a modified split_pack function. -# """ -# def __init__(self): -# OpToVectorOp.__init__(self, (None, None, TypeRestrict()), None) -# self.has_descr = True -# -# def must_be_full_but_is_not(self, pack): -# vrs = self.sched_data.vec_reg_size -# it = pack.input_type -# return it.getsize() * it.getcount() < vrs -# -# def get_output_type_given(self, input_type, op): -# return None -# -# def get_input_type_given(self, output_type, op): -# return xxx#Type.by_descr(op.getdescr(), self.sched_data.vec_reg_size) -# -#class PassThroughOp(OpToVectorOp): -# """ This pass through is only applicable if the target -# operation is capable of handling vector operations. -# Guard true/false is such an example. -# """ -# def __init__(self, args): -# OpToVectorOp.__init__(self, args, None) -# -# def get_output_type_given(self, input_type, op): -# return None -# -# def get_input_type_given(self, output_type, op): -# raise AssertionError("cannot infer input type from output type") -# -# -# -##def determine_input_output_types(pack, node, forward): -## """ This function is two fold. If moving forward, it -## gets an input type from the packs output type and returns -## the transformed packtype. -## -## Moving backward, the origins pack input type is the output -## type and the transformation of the packtype (in reverse direction) -## is the input -## """ -## op = node.getoperation() -## op2vecop = determine_trans(op) -## if forward: -## input_type = op2vecop.force_input(pack.output_type) -## output_type = op2vecop.get_output_type_given(input_type, op) -## if output_type: -## output_type = output_type.clone() -## else: -## # going backwards, things are not that easy anymore -## output_type = pack.input_type -## input_type = op2vecop.get_input_type_given(output_type, op) -## if input_type: -## input_type = input_type.clone() -## -## return input_type, output_type -# -#def determine_trans(op): -# op2vecop = trans.MAPPING.get(op.vector, None) -# if op2vecop is None: -# raise NotImplementedError("missing vecop for '%s'" % (op.getopname(),)) -# return op2vecop +#def extend_int(self, vbox, newtype): +# vbox_cloned = newtype.new_vector_box(vbox.getcount()) +# self.sched_data._prevent_signext(newtype.getsize(), vbox.getsize()) +# newsize = newtype.getsize() +# assert newsize > 0 +# op = ResOperation(rop.VEC_INT_SIGNEXT, +# [vbox, ConstInt(newsize)], +# vbox_cloned) +# self.costmodel.record_cast_int(vbox.getsize(), newtype.getsize(), vbox.getcount()) +# self.vecops.append(op) +# return vbox_cloned - -#def before_argument_transform(self, args): -# pass - -#def transform_result(self, result): -# if result is None: -# return None -# vbox = self.new_result_vector_box() -# # -# # mark the position and the vbox in the hash -# for i, node in enumerate(self.getoperations()): -# if i >= vbox.getcount(): -# break -# op = node.getoperation() -# self.sched_data.setvector_of_box(op, i, vbox) -# return vbox - -#def new_result_vector_box(self): -# type = self.output_type.gettype() -# size = self.output_type.getsize() -# count = min(self.output_type.getcount(), len(self.pack.operations)) -# signed = self.output_type.signed -# return BoxVector(type, count, size, signed) - -#def getoperations(self): -# return self.pack.operations - -#def transform_arguments(self, args): -# """ Transforming one argument to a vector box argument -# The following cases can occur: -# 1) argument is present in the box_to_vbox map. -# a) vector can be reused immediatly (simple case) -# b) vector is to big -# c) vector is to small -# 2) argument is not known to reside in a vector -# a) expand vars/consts before the label and add as argument -# b) expand vars created in the loop body -# """ -# for i,arg in enumerate(args): -# if arg.returns_vector(): -# continue -# if not self.is_vector_arg(i): -# continue -# box_pos, vbox = self.sched_data.getvector_of_box(arg) -# if not vbox: -# # constant/variable expand this box -# vbox = self.expand(arg, i) -# self.sched_data.setvector_of_box(arg, 0, vbox) -# box_pos = 0 -# # convert size i64 -> i32, i32 -> i64, ... -# if self.input_type.getsize() > 0 and \ -# self.input_type.getsize() != vbox.getsize(): -# vbox = self.extend(vbox, self.input_type) - -# # use the input as an indicator for the pack type -# packable = self.input_type.getcount() -# packed = vbox.getcount() -# assert packed >= 0 -# assert packable >= 0 -# if packed > packable: -# # the argument has more items than the operation is able to process! -# # box_pos == 0 then it is already at the right place -# if box_pos != 0: -# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# remember_args_in_vector(i, args[i]) -# #self.update_input_output(self.pack) -# continue -# else: -# assert vbox is not None -# args[i] = vbox -# continue -# vboxes = self.vector_boxes_for_args(i) -# if packed < packable and len(vboxes) > 1: -# # the argument is scattered along different vector boxes -# args[i] = self.gather(vboxes, packable) -# remember_args_in_vector(i, args[i]) -# continue -# if box_pos != 0: -# # The vector box is at a position != 0 but it -# # is required to be at position 0. Unpack it! -# args[i] = self.unpack(vbox, box_pos, packed - box_pos, self.input_type) -# remember_args_in_vector(i, args[i]) -# continue -# #self.update_input_output(self.pack) -# # -# assert vbox is not None -# args[i] = vbox diff --git a/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py b/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py --- a/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py @@ -2,14 +2,15 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.util import equaloplists -from rpython.jit.metainterp.optimizeopt.vectorize import (VecScheduleData, - Pack, NotAProfitableLoop, VectorizingOptimizer) +from rpython.jit.metainterp.optimizeopt.vector import (Pack, X86_CostModel, + NotAProfitableLoop, VectorizingOptimizer) +from rpython.jit.metainterp.optimizeopt.schedule import VecScheduleState from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_schedule import SchedulerBaseTest -from rpython.jit.metainterp.optimizeopt.test.test_vectorize import (FakeMetaInterpStaticData, +from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, FakeJitDriverStaticData) -from rpython.jit.metainterp.resoperation import rop, ResOperation +from rpython.jit.metainterp.resoperation import rop, ResOperation, AbstractValue from rpython.jit.tool.oparser import parse as opparse from rpython.jit.tool.oparser_model import get_model @@ -18,7 +19,7 @@ self.index_var = iv self.array = array - def is_adjacent_to(self, other): + def is_adjacent_after(self, other): if self.array is not other.array: return False iv = self.index_var @@ -28,36 +29,39 @@ # i1 and i0 ... # but not i0, i2 # ... - return abs(val) == 1 + print iv, 'is after', ov, "?", val == 1 + return val == 1 class CostModelBaseTest(SchedulerBaseTest): + def savings(self, loop): metainterp_sd = FakeMetaInterpStaticData(self.cpu) jitdriver_sd = FakeJitDriverStaticData() - opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, loop, []) - label_index = loop.find_first_index(rop.LABEL) - opt.orig_label_args = loop.operations[label_index].getarglist()[:] + opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, 0) + opt.orig_label_args = loop.label.getarglist()[:] graph = opt.dependency_graph = DependencyGraph(loop) + self.show_dot_graph(graph, 'costmodel') for k,m in graph.memory_refs.items(): graph.memory_refs[k] = FakeMemoryRef(m.array, m.index_var) - opt.find_adjacent_memory_refs() + opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() for pack in opt.packset.packs: print "pack: \n ", print '\n '.join([str(op.getoperation()) for op in pack.operations]) print - opt.costmodel.reset_savings() - opt.schedule(True) - return opt.costmodel.savings + costmodel = X86_CostModel(self.cpu, 0) + state = VecScheduleState(graph, opt.packset, self.cpu, costmodel) + opt.schedule(state) + return costmodel.savings def assert_operations_match(self, loop_a, loop_b): assert equaloplists(loop_a.operations, loop_b.operations) def test_load_2_unpack(self): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) guard_true(i0) [f10] guard_true(i1) [f11] """) @@ -68,11 +72,11 @@ assert savings == -2 def test_load_4_unpack(self): - loop1 = self.parse(""" - i10 = raw_load(p0, i0, descr=float) - i11 = raw_load(p0, i1, descr=float) - i12 = raw_load(p0, i2, descr=float) - i13 = raw_load(p0, i3, descr=float) + loop1 = self.parse_trace(""" + i10 = raw_load_i(p0, i0, descr=float) + i11 = raw_load_i(p0, i1, descr=float) + i12 = raw_load_i(p0, i2, descr=float) + i13 = raw_load_i(p0, i3, descr=float) guard_true(i0) [i10] guard_true(i1) [i11] guard_true(i2) [i12] @@ -82,29 +86,29 @@ assert savings == -1 def test_load_2_unpack_1(self): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) guard_true(i0) [f10] """) savings = self.savings(loop1) assert savings == 0 def test_load_2_unpack_1_index1(self): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) guard_true(i0) [f11] """) savings = self.savings(loop1) assert savings == -1 - def test_load_arith(self): - loop1 = self.parse(""" - i10 = raw_load(p0, i0, descr=int) - i11 = raw_load(p0, i1, descr=int) - i12 = raw_load(p0, i2, descr=int) - i13 = raw_load(p0, i3, descr=int) + def test_load_arith1(self): + loop1 = self.parse_trace(""" + i10 = raw_load_i(p0, i0, descr=int) + i11 = raw_load_i(p0, i1, descr=int) + i12 = raw_load_i(p0, i2, descr=int) + i13 = raw_load_i(p0, i3, descr=int) i15 = int_add(i10, 1) i16 = int_add(i11, 1) i17 = int_add(i12, 1) @@ -114,9 +118,9 @@ assert savings == 6 def test_load_arith_store(self): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) i20 = cast_float_to_int(f10) i21 = cast_float_to_int(f11) i30 = int_signext(i20, 4) @@ -128,9 +132,9 @@ assert savings >= 0 def test_sum(self): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) f12 = float_add(f1, f10) f13 = float_add(f12, f11) """) @@ -139,9 +143,9 @@ @py.test.mark.parametrize("bytes,s", [(1,None),(2,None),(4,0),(8,0)]) def test_sum_float_to_int(self, bytes, s): - loop1 = self.parse(""" - f10 = raw_load(p0, i0, descr=double) - f11 = raw_load(p0, i1, descr=double) + loop1 = self.parse_trace(""" + f10 = raw_load_f(p0, i0, descr=double) + f11 = raw_load_f(p0, i1, descr=double) i10 = cast_float_to_int(f10) i11 = cast_float_to_int(f11) i12 = int_signext(i10, {c}) @@ -166,20 +170,20 @@ py.test.fail("must not fail") def test_cast(self): - loop1 = self.parse(""" - i100 = raw_load(p0, i1, descr=float) - i101 = raw_load(p0, i2, descr=float) - i102 = raw_load(p0, i3, descr=float) - i103 = raw_load(p0, i4, descr=float) + loop1 = self.parse_trace(""" + i100 = raw_load_i(p0, i1, descr=float) + i101 = raw_load_i(p0, i2, descr=float) + i102 = raw_load_i(p0, i3, descr=float) + i103 = raw_load_i(p0, i4, descr=float) # - i104 = raw_load(p1, i1, descr=short) - i105 = raw_load(p1, i2, descr=short) - i106 = raw_load(p1, i3, descr=short) - i107 = raw_load(p1, i4, descr=short) - i108 = raw_load(p1, i5, descr=short) - i109 = raw_load(p1, i6, descr=short) - i110 = raw_load(p1, i7, descr=short) - i111 = raw_load(p1, i8, descr=short) + i104 = raw_load_i(p1, i1, descr=short) + i105 = raw_load_i(p1, i2, descr=short) + i106 = raw_load_i(p1, i3, descr=short) + i107 = raw_load_i(p1, i4, descr=short) + i108 = raw_load_i(p1, i5, descr=short) + i109 = raw_load_i(p1, i6, descr=short) + i110 = raw_load_i(p1, i7, descr=short) + i111 = raw_load_i(p1, i8, descr=short) # f100 = cast_int_to_float(i104) f101 = cast_int_to_float(i105) @@ -192,7 +196,7 @@ """) try: self.savings(loop1) - py.test.fail("must not profitable!") + py.test.fail("must not be profitable!") except NotAProfitableLoop: pass diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -6,6 +6,7 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, Dependency, IndexVar, MemoryRef, Node) +from rpython.jit.metainterp.compile import ResumeAtLoopHeaderDescr from rpython.jit.metainterp.optimizeopt.vector import VectorLoop from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.backend.llgraph.runner import ArrayDescr @@ -54,7 +55,7 @@ loop.jump.setdescr(token) for op in loop.operations: if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: - op.setdescr(compile.ResumeAtLoopHeaderDescr()) + op.setdescr(ResumeAtLoopHeaderDescr()) return loop def assert_edges(self, graph, edge_list, exceptions): diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -29,6 +29,8 @@ from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import Counters from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.llsupport.symbolic import (WORD as INT_WORD, + SIZEOF_FLOAT as FLOAT_WORD) class VectorLoop(object): def __init__(self, label, oplist, jump): @@ -188,7 +190,7 @@ # vectorize graph = DependencyGraph(loop) - self.find_adjacent_memory_refs() + self.find_adjacent_memory_refs(graph) self.extend_packset() self.combine_packset() # TODO move cost model to CPU @@ -256,7 +258,7 @@ if op.getopnum() in prohibit_opnums: continue # do not unroll this operation twice copied_op = op.clone() - if copied_op.result is not None: + if not copied_op.returns_void(): # every result assigns a new box, thus creates an entry # to the rename map. new_assigned_box = copied_op.result.clonebox() @@ -323,7 +325,7 @@ They are represented as a linear combination: i*c/d + e, i is a variable, all others are integers that are calculated in reverse direction """ - loop = self.loop + loop = graph.loop operations = loop.operations self.packset = PackSet(self.cpu.vector_register_size) @@ -338,8 +340,10 @@ # exclue a_opidx == b_opidx only consider the ones # that point forward: if memref_a.is_adjacent_after(memref_b): + print node_a.getindex(), "is after", node_b.getindex() pair = self.packset.can_be_packed(node_a, node_b, None, False) if pair: + print "creating mem pair", pair self.packset.add_pack(pair) def extend_packset(self): @@ -348,26 +352,33 @@ """ pack_count = self.packset.pack_count() while True: - for pack in self.packset.packs: + i = 0 + packs = self.packset.packs + while i < len(packs): + pack = packs[i] self.follow_def_uses(pack) + i += 1 if pack_count == self.packset.pack_count(): pack_count = self.packset.pack_count() - for pack in self.packset.packs: + i = 0 + while i < len(packs): + pack = packs[i] self.follow_use_defs(pack) + i += 1 if pack_count == self.packset.pack_count(): break pack_count = self.packset.pack_count() def follow_use_defs(self, pack): assert isinstance(pack, Pair) - for ldep in pack.left.depends(): - for rdep in pack.right.depends(): + for ldep in pack.leftmost(True).depends(): + for rdep in pack.rightmost(True).depends(): lnode = ldep.to rnode = rdep.to - # only valid if the result of the left is in args of pack left - result = lnode.getoperation().result - args = pack.left.getoperation().getarglist() - if result is None or result not in args: + # only valid if left is in args of pack left + left = lnode.getoperation() + args = pack.leftmost().getarglist() + if left is None or left not in args: continue isomorph = isomorphic(lnode.getoperation(), rnode.getoperation()) if isomorph and lnode.is_before(rnode): @@ -377,19 +388,25 @@ def follow_def_uses(self, pack): assert isinstance(pack, Pair) - for ldep in pack.left.provides(): - for rdep in pack.right.provides(): + print "lprov", pack.leftmost(node=True).provides_count(), + print "rprov", pack.rightmost(node=True).provides_count() + for ldep in pack.leftmost(node=True).provides(): + for rdep in pack.rightmost(node=True).provides(): lnode = ldep.to rnode = rdep.to - result = pack.left.getoperation().result + print "trying", lnode.getindex(), rnode.getindex(), lnode, rnode + left = pack.leftmost() args = lnode.getoperation().getarglist() - if result is None or result not in args: + if left is None or left not in args: continue isomorph = isomorphic(lnode.getoperation(), rnode.getoperation()) if isomorph and lnode.is_before(rnode): pair = self.packset.can_be_packed(lnode, rnode, pack, True) if pair: + print "creating pair" , pair, pair.operations[0].op, pair.operations[1].op self.packset.add_pack(pair) + else: + print "!!!creating pair" , lnode, rnode def combine_packset(self): """ Combination is done iterating the packs that have @@ -404,7 +421,6 @@ i = 0 j = 0 end_ij = len(self.packset.packs) - orphan = {} while True: len_before = len(self.packset.packs) i = 0 @@ -616,6 +632,7 @@ cost, benefit_factor = self.cb_signext(pack) # self.savings += benefit_factor * times - cost + print "$$$ recording", benefit_factor, "*", times, "-", cost, "now:", self.savings def cb_signext(self, pack): left = pack.leftmost() @@ -627,13 +644,16 @@ def record_cast_int(self, fromsize, tosize, count): # for each move there is 1 instruction self.savings += -count + print "$$$ cast", -count, "now", self.savings def record_vector_pack(self, src, index, count): if src.datatype == FLOAT: if index == 1 and count == 1: self.savings -= 2 + print "$$$ vector pack -2 now:", self.savings return self.savings -= count + print "$$$ vector pack ", count, "now", self.savings def record_vector_unpack(self, src, index, count): self.record_vector_pack(src, index, count) @@ -680,6 +700,7 @@ if self.profitable_pack(lnode, rnode, origin_pack, forward): return Pair(lnode, rnode) else: + print "dependent" if self.contains_pair(lnode, rnode): return None if origin_pack is not None: @@ -688,24 +709,18 @@ def contains_pair(self, lnode, rnode): for pack in self.packs: - if pack.left is lnode or pack.right is rnode: + if pack.leftmost(node=True) is lnode or \ + pack.rightmost(node=True) is rnode: return True return False def profitable_pack(self, lnode, rnode, origin_pack, forward): - lpacknode = origin_pack.left - if self.prohibit_packing(origin_pack, - lpacknode.getoperation(), - lnode.getoperation(), - forward): + if self.prohibit_packing(origin_pack, origin_pack.leftmost(), + lnode.getoperation(), forward): return False - rpacknode = origin_pack.right - if self.prohibit_packing(origin_pack, - rpacknode.getoperation(), - rnode.getoperation(), - forward): + if self.prohibit_packing(origin_pack, origin_pack.rightmost(), + rnode.getoperation(), forward): return False - return True def prohibit_packing(self, pack, packed, inquestion, forward): @@ -713,7 +728,7 @@ if inquestion.vector == -1: return True if packed.is_primitive_array_access(): - if packed.getarg(1) == inquestion.result: + if packed.getarg(1) is inquestion: return True if not forward and inquestion.getopnum() == rop.INT_SIGNEXT: # prohibit the packing of signext in backwards direction @@ -742,37 +757,37 @@ def accumulates_pair(self, lnode, rnode, origin_pack): # lnode and rnode are isomorphic and dependent assert isinstance(origin_pack, Pair) - lop = lnode.getoperation() - opnum = lop.getopnum() + left = lnode.getoperation() + opnum = left.getopnum() if opnum in (rop.FLOAT_ADD, rop.INT_ADD, rop.FLOAT_MUL): - roper = rnode.getoperation() - assert lop.numargs() == 2 and lop.result is not None - accum_var, accum_pos = self.getaccumulator_variable(lop, roper, origin_pack) + right = rnode.getoperation() + assert left.numargs() == 2 and not left.returns_void() + accum_var, accum_pos = self.getaccumulator_variable(left, right, origin_pack) if not accum_var: return None - # the dependency exists only because of the result of lnode + # the dependency exists only because of the left? for dep in lnode.provides(): if dep.to is rnode: if not dep.because_of(accum_var): # not quite ... this is not handlable return None # get the original variable - accum_var = lop.getarg(accum_pos) + accum_var = left.getarg(accum_pos) # in either of the two cases the arguments are mixed, # which is not handled currently var_pos = (accum_pos + 1) % 2 - plop = origin_pack.left.getoperation() - if lop.getarg(var_pos) is not plop.result: + if left.getarg(var_pos) is not origin_pack.leftmost(): return None - prop = origin_pack.right.getoperation() - if roper.getarg(var_pos) is not prop.result: + if right.getarg(var_pos) is not origin_pack.rightmost(): return None # this can be handled by accumulation - ptype = origin_pack.output_type - if ptype.getsize() != 8: + size = INT_WORD + if left.type == 'f': + size = FLOAT_WORD + if left.bytesize == right.bytesize and left.bytesize == size: # do not support if if the type size is smaller # than the cpu word size. # WHY? @@ -781,16 +796,14 @@ # considered. => tree pattern matching problem. return None accum = Accum(opnum, accum_var, accum_pos) - return AccumPair(lnode, rnode, ptype, ptype, accum) + return AccumPair(lnode, rnode, accum) return None - def getaccumulator_variable(self, lop, rop, origin_pack): - args = rop.getarglist() - for i, arg in enumerate(args): - if arg is lop.result: + def getaccumulator_variable(self, left, right, origin_pack): + for i, arg in enumerate(right.getarglist()): + if arg is left: return arg, i - # return None, -1 def accumulate_prepare(self, state): diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -147,6 +147,11 @@ i += 1 arg = self.getarg(i) if arg.is_constant(): + if arg.type == 'i': + self.setdatatype('i', INT_WORD, True) + else: + assert arg.type == 'f' + self.setdatatype('f', FLOAT_WORD, False) return self.setdatatype(arg.datatype, arg.bytesize, arg.signed) assert self.datatype != '\x00' diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -198,6 +198,8 @@ from rpython.rtyper.lltypesystem import lltype, llmemory assert elem.startswith('p') v = InputArgRef(lltype.nullptr(llmemory.GCREF.TO)) + # ensure that the variable gets the proper naming + self.update_memo(v, elem) self.vars[elem] = v return v @@ -353,9 +355,24 @@ raise ParseError("Double assign to var %s in line: %s" % (res, line)) resop = self.create_op(opnum, args, res, descr, fail_args) res = self.update_vector(resop, res) + self.update_memo(resop, res) self.vars[res] = resop return resop + def update_memo(self, val, name): + """ This updates the id of the operation or inputarg. + Internally you will see the same variable names as + in the trace as string. + """ + regex = re.compile("[prif](\d+)") + match = regex.match(name) + if match: + counter = int(match.group(1)) + countdict = val._repr_memo + countdict._d[val] = counter + if countdict.counter < counter: + countdict.counter = counter + def update_vector(self, resop, var): pattern = re.compile('.*\[(\d+)x(u?)(i|f)(\d+)\]') match = pattern.match(var) From noreply at buildbot.pypy.org Wed Sep 16 18:58:44 2015 From: noreply at buildbot.pypy.org (cfbolz) Date: Wed, 16 Sep 2015 18:58:44 +0200 (CEST) Subject: [pypy-commit] pypy value-profiling: merge default Message-ID: <20150916165844.A584B1C12D6@cobra.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: value-profiling Changeset: r79659:eac19bbcfe06 Date: 2015-09-16 18:58 +0200 http://bitbucket.org/pypy/pypy/changeset/eac19bbcfe06/ Log: merge default diff too long, truncating to 2000 out of 51112 lines diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -15,3 +15,4 @@ e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 e03971291f3a0729ecd3ee7fae7ddb0bb82d476c release-2.6.0 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0 +f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -168,7 +168,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -215,6 +214,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -247,6 +247,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -352,8 +353,7 @@ Except when otherwise stated (look for LICENSE files or copyright/license information at the beginning of each file) the files in the 'lib-python/2.7' directory are all copyrighted by the Python Software Foundation and licensed -under the Python Software License of which you can find a copy here: -http://www.python.org/doc/Copyright.html +under the terms that you can find here: https://docs.python.org/2/license.html License for 'pypy/module/unicodedata/' ====================================== @@ -430,9 +430,9 @@ gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license as well. -License for 'pypy/module/_vmprof/src' +License for 'rpython/rlib/rvmprof/src' -------------------------------------- The code is based on gperftools. You may see a copy of the License for it at - https://code.google.com/p/gperftools/source/browse/COPYING + https://github.com/gperftools/gperftools/blob/master/COPYING diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -303,7 +303,7 @@ RegrTest('test_memoryio.py'), RegrTest('test_memoryview.py'), RegrTest('test_md5.py'), - RegrTest('test_mhlib.py'), + RegrTest('test_mhlib.py', usemodules='binascii struct'), RegrTest('test_mimetools.py'), RegrTest('test_mimetypes.py'), RegrTest('test_MimeWriter.py', core=False, usemodules='binascii'), diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py --- a/lib_pypy/_curses.py +++ b/lib_pypy/_curses.py @@ -1026,16 +1026,22 @@ def tigetflag(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetflag(capname) def tigetnum(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') return lib.tigetnum(capname) def tigetstr(capname): _ensure_initialised_setupterm() + if isinstance(capname, unicode): + capname = capname.encode('ascii') val = lib.tigetstr(capname) if int(ffi.cast("intptr_t", val)) in (0, -1): return None diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.2.0 +Version: 1.3.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.2.0" -__version_info__ = (1, 2, 0) +__version__ = "1.3.0" +__version_info__ = (1, 3, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -46,7 +46,7 @@ # endif #else # include -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) # include # endif #endif @@ -214,6 +214,12 @@ (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ _CFFI__UNKNOWN_PRIM) +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + #define _cffi_check_int(got, got_nonpos, expected) \ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py --- a/lib_pypy/cffi/cffi_opcode.py +++ b/lib_pypy/cffi/cffi_opcode.py @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -15,9 +15,11 @@ except ImportError: lock = None -_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) -_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", - re.MULTILINE) +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") @@ -39,6 +41,7 @@ macros = {} for match in _r_define.finditer(csource): macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() macros[macroname] = macrovalue csource = _r_define.sub('', csource) # Replace "[...]" with "[__dotdotdotarray__]" @@ -423,13 +426,10 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - elif (len(params) == 1 and - isinstance(params[0].type, pycparser.c_ast.TypeDecl) and - isinstance(params[0].type.type, pycparser.c_ast.IdentifierType) - and list(params[0].type.type.names) == ['void']): - del params[0] args = [self._as_func_arg(self._get_type(argdeclnode.type)) for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] result = self._get_type(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) @@ -648,10 +648,21 @@ assert typenames[-1] == '__dotdotdot__' if len(typenames) == 1: return model.unknown_type(decl.name) - for t in typenames[:-1]: - if t not in ['int', 'short', 'long', 'signed', 'unsigned', 'char']: - raise api.FFIError(':%d: bad usage of "..."' % decl.coord.line) + + if (typenames[:-1] == ['float'] or + typenames[:-1] == ['double']): + # not for 'long double' so far + result = model.UnknownFloatType(decl.name) + else: + for t in typenames[:-1]: + if t not in ['int', 'short', 'long', 'signed', + 'unsigned', 'char']: + raise api.FFIError(':%d: bad usage of "..."' % + decl.coord.line) + result = model.UnknownIntegerType(decl.name) + if self._uses_new_feature is None: self._uses_new_feature = "'typedef %s... %s'" % ( ' '.join(typenames[:-1]), decl.name) - return model.UnknownIntegerType(decl.name) + + return result diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -158,12 +158,23 @@ self.c_name_with_marker = name + '&' def is_integer_type(self): - return True # for now + return True def build_backend_type(self, ffi, finishlist): raise NotImplementedError("integer type '%s' can only be used after " "compilation" % self.name) +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + class BaseFunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h --- a/lib_pypy/cffi/parse_c_type.h +++ b/lib_pypy/cffi/parse_c_type.h @@ -79,7 +79,9 @@ #define _CFFI_PRIM_UINTMAX 47 #define _CFFI__NUM_PRIM 48 -#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) struct _cffi_global_s { diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -4,11 +4,6 @@ VERSION = "0x2601" -try: - int_type = (int, long) -except NameError: # Python 3 - int_type = int - class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): @@ -473,6 +468,10 @@ if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), tp.name.replace(' ', '_')) @@ -527,6 +526,8 @@ if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type(): return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double': return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: @@ -1112,6 +1113,12 @@ ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -81,10 +81,16 @@ allsources.extend(kwds.pop('sources', [])) ext = Extension(name=module_name, sources=allsources, **kwds) - def make_mod(tmpdir): + def make_mod(tmpdir, pre_run=None): c_file = os.path.join(tmpdir, module_name + source_extension) log.info("generating cffi module %r" % c_file) mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) updated = recompiler.make_c_source(ffi, module_name, source, c_file) if not updated: log.info("already up-to-date") @@ -98,7 +104,8 @@ class build_ext_make_mod(base_class): def run(self): if ext.sources[0] == '$PLACEHOLDER': - ext.sources[0] = make_mod(self.build_temp) + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) base_class.run(self) dist.cmdclass['build_ext'] = build_ext_make_mod # NB. multiple runs here will create multiple 'build_ext_make_mod' diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py --- a/lib_pypy/ctypes_support.py +++ b/lib_pypy/ctypes_support.py @@ -28,7 +28,7 @@ def _where_is_errno(): return standard_c_lib.__errno_location() -elif sys.platform in ('darwin', 'freebsd7', 'freebsd8', 'freebsd9'): +elif sys.platform == 'darwin' or sys.platform.startswith('freebsd'): standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int) standard_c_lib.__error.argtypes = None def _where_is_errno(): diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info --- a/lib_pypy/greenlet.egg-info +++ b/lib_pypy/greenlet.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: greenlet -Version: 0.4.7 +Version: 0.4.9 Summary: Lightweight in-process concurrent programming Home-page: https://github.com/python-greenlet/greenlet Author: Ralf Schmitt (for CPython), PyPy team diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py --- a/lib_pypy/greenlet.py +++ b/lib_pypy/greenlet.py @@ -1,7 +1,7 @@ import sys import _continuation -__version__ = "0.4.7" +__version__ = "0.4.9" # ____________________________________________________________ # Exceptions diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,7 +39,8 @@ "_csv", "cppyy", "_pypyjson" ]) -if sys.platform.startswith('linux') and os.uname()[4] == 'x86_64': +if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' + and sys.maxint > 2**32): # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -67,7 +67,7 @@ # The short X.Y version. version = '2.6' # The full version, including alpha/beta/rc tags. -release = '2.6.0' +release = '2.6.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -32,6 +32,7 @@ Lukas Diekmann Sven Hager Anders Lehmann + Richard Plangger Aurelien Campeas Remi Meier Niklaus Haldimann @@ -57,7 +58,6 @@ Ludovic Aubry Jacob Hallen Jason Creighton - Richard Plangger Alex Martelli Michal Bendowski stian @@ -138,7 +138,6 @@ Michael Twomey Lucian Branescu Mihaila Yichao Yu - Anton Gulenko Gabriel Lavoie Olivier Dormond Jared Grubb @@ -185,6 +184,7 @@ Carl Meyer Karl Ramm Pieter Zieschang + Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -217,6 +217,7 @@ Toni Mattis Lucas Stadler Julian Berman + Markus Holtermann roberto at goyle Yury V. Zaytsev Anna Katrina Dominguez @@ -252,6 +253,7 @@ shoma hosaka Daniel Neuhäuser Ben Mather + Niclas Olofsson halgari Boglarka Vezer Chris Pressey diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -20,10 +20,6 @@ It initializes the RPython/PyPy GC and does a bunch of necessary startup code. This function cannot fail. -.. function:: void pypy_init_threads(void); - - Initialize threads. Only need to be called if there are any threads involved - .. function:: int pypy_setup_home(char* home, int verbose); This function searches the PyPy standard library starting from the given @@ -38,6 +34,11 @@ Function returns 0 on success or -1 on failure, can be called multiple times until the library is found. +.. function:: void pypy_init_threads(void); + + Initialize threads. Only need to be called if there are any threads involved. + *Must be called after pypy_setup_home()* + .. function:: int pypy_execute_source(char* source); Execute the Python source code given in the ``source`` argument. In case of diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -31,15 +31,14 @@ and add the new file to pypy/doc/index-of-whatsnew.rst * go to pypy/tool/release and run ``force-builds.py `` - The following binaries should be built, however, we need more buildbots - - JIT: windows, linux, os/x, armhf, armel - - no JIT: windows, linux, os/x - - sandbox: linux, os/x + The following JIT binaries should be built, however, we need more buildbots + windows, linux-32, linux-64, osx64, armhf-raring, armhf-raspberrian, armel, + freebsd64 * wait for builds to complete, make sure there are no failures * download the builds, repackage binaries. Tag the release version and download and repackage source from bitbucket. You may find it - convenient to use the ``repackage.sh`` script in pypy/tools to do this. + convenient to use the ``repackage.sh`` script in pypy/tool/release to do this. Otherwise repackage and upload source "-src.tar.bz2" to bitbucket and to cobra, as some packagers prefer a clearly labeled source package diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-2.6.1.rst release-2.6.0.rst release-2.5.1.rst release-2.5.0.rst diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-2.6.1.rst whatsnew-2.6.0.rst whatsnew-2.5.1.rst whatsnew-2.5.0.rst diff --git a/pypy/doc/release-2.6.1.rst b/pypy/doc/release-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.6.1.rst @@ -0,0 +1,129 @@ +========== +PyPy 2.6.1 +========== + +We're pleased to announce PyPy 2.6.1, an update to PyPy 2.6.0 released June 1. +We have updated stdlib to 2.7.10, `cffi`_ to version 1.3, extended support for +the new vmprof_ statistical profiler for multiple threads, and increased +functionality of numpy. + +You can download the PyPy 2.6.1 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and our volunteers and contributors. + +.. _`cffi`: https://cffi.readthedocs.org + +We would also like to encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ with making +RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD_, freebsd_), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +.. _`pypy and cpython 2.7.x`: http://speed.pypy.org +.. _OpenBSD: http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/pypy +.. _freebsd: https://svnweb.freebsd.org/ports/head/lang/pypy/ +.. _`dynamic languages`: http://pypyjs.org + +Highlights +=========== + +* Bug Fixes + + * Revive non-SSE2 support + + * Fixes for detaching _io.Buffer* + + * On Windows, close (and flush) all open sockets on exiting + + * Drop support for ancient macOS v10.4 and before + + * Clear up contention in the garbage collector between trace-me-later and pinning + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy. + +* New features: + + * cffi was updated to version 1.3 + + * The python stdlib was updated to 2.7.10 from 2.7.9 + + * vmprof now supports multiple threads and OS X + + * The translation process builds cffi import libraries for some stdlib + packages, which should prevent confusion when package.py is not used + + * better support for gdb debugging + + * freebsd should be able to translate PyPy "out of the box" with no patches + +* Numpy: + + * Better support for record dtypes, including the ``align`` keyword + + * Implement casting and create output arrays accordingly (still missing some corner cases) + + * Support creation of unicode ndarrays + + * Better support ndarray.flags + + * Support ``axis`` argument in more functions + + * Refactor array indexing to support ellipses + + * Allow the docstrings of built-in numpy objects to be set at run-time + + * Support the ``buffered`` nditer creation keyword + +* Performance improvements: + + * Delay recursive calls to make them non-recursive + + * Skip loop unrolling if it compiles too much code + + * Tweak the heapcache + + * Add a list strategy for lists that store both floats and 32-bit integers. + The latter are encoded as nonstandard NaNs. Benchmarks show that the speed + of such lists is now very close to the speed of purely-int or purely-float + lists. + + * Simplify implementation of ffi.gc() to avoid most weakrefs + + * Massively improve the performance of map() with more than + one sequence argument + +.. _`vmprof`: https://vmprof.readthedocs.org +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-2.6.1.html + +Please try it out and let us know what you think. We welcome +success stories, `experiments`_, or `benchmarks`_, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + +.. _`experiments`: https://morepypy.blogspot.com/2015/02/experiments-in-pyrlang-with-rpython.html +.. _`benchmarks`: https://mithrandi.net/blog/2015/03/axiom-benchmark-results-on-pypy-2-5-0 diff --git a/pypy/doc/whatsnew-2.6.1.rst b/pypy/doc/whatsnew-2.6.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-2.6.1.rst @@ -0,0 +1,76 @@ +======================== +What's new in PyPy 2.6.1 +======================== + +.. this is a revision shortly after release-2.6.0 +.. startrev: 91904d5c5188 + +.. branch: use_min_scalar +Correctly resolve the output dtype of ufunc(array, scalar) calls. + +.. branch: stdlib-2.7.10 + +Update stdlib to version 2.7.10 + +.. branch: issue2062 + +.. branch: disable-unroll-for-short-loops +The JIT no longer performs loop unrolling if the loop compiles to too much code. + +.. branch: run-create_cffi_imports + +Build cffi import libraries as part of translation by monkey-patching an +additional task into translation + +.. branch: int-float-list-strategy + +Use a compact strategy for Python lists that mix integers and floats, +at least if the integers fit inside 32 bits. These lists are now +stored as an array of floats, like lists that contain only floats; the +difference is that integers are stored as tagged NaNs. (This should +have no visible effect! After ``lst = [42, 42.5]``, the value of +``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) + +.. branch: cffi-callback-onerror +Part of cffi 1.2. + +.. branch: cffi-new-allocator +Part of cffi 1.2. + +.. branch: unicode-dtype + +Partial implementation of unicode dtype and unicode scalars. + +.. branch: dtypes-compatability + +Improve compatibility with numpy dtypes; handle offsets to create unions, +fix str() and repr(), allow specifying itemsize, metadata and titles, add flags, +allow subclassing dtype + +.. branch: indexing + +Refactor array indexing to support ellipses. + +.. branch: numpy-docstrings + +Allow the docstrings of built-in numpy objects to be set at run-time. + +.. branch: nditer-revisited + +Implement nditer 'buffered' flag and fix some edge cases + +.. branch: ufunc-reduce + +Allow multiple axes in ufunc.reduce() + +.. branch: fix-tinylang-goals + +Update tinylang goals to match current rpython + +.. branch: vmprof-review + +Clean up of vmprof, notably to handle correctly multiple threads + +.. branch: no_boehm_dl + +Remove extra link library from Boehm 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 @@ -2,68 +2,22 @@ What's new in PyPy 2.6+ ======================= -.. this is a revision shortly after release-2.6.0 -.. startrev: 91904d5c5188 +.. this is a revision shortly after release-2.6.1 +.. startrev: 07769be4057b -.. branch: use_min_scalar -Correctly resolve the output dtype of ufunc(array, scalar) calls. +.. branch: keys_with_hash +Improve the performance of dict.update() and a bunch of methods from +sets, by reusing the hash value stored in one dict when inspecting +or changing another dict with that key. -.. branch: stdlib-2.7.10 +.. branch: optresult-unroll +A major refactoring of the ResOperations that kills Box. Also rewrote +unrolling to enable future enhancements. Should improve warmup time +by 20% or so. -Update stdlib to version 2.7.10 +.. branch: optimize-cond-call +Optimize common sequences of operations like +``int_lt/cond_call`` in the JIT backends -.. branch: issue2062 - -.. branch: disable-unroll-for-short-loops -The JIT no longer performs loop unrolling if the loop compiles to too much code. - -.. branch: run-create_cffi_imports - -Build cffi import libraries as part of translation by monkey-patching an -additional task into translation - -.. branch: int-float-list-strategy - -Use a compact strategy for Python lists that mix integers and floats, -at least if the integers fit inside 32 bits. These lists are now -stored as an array of floats, like lists that contain only floats; the -difference is that integers are stored as tagged NaNs. (This should -have no visible effect! After ``lst = [42, 42.5]``, the value of -``lst[0]`` is still *not* the float ``42.0`` but the integer ``42``.) - -.. branch: cffi-callback-onerror -.. branch: cffi-new-allocator - -.. branch: unicode-dtype - -Partial implementation of unicode dtype and unicode scalars. - -.. branch: dtypes-compatability - -Improve compatibility with numpy dtypes; handle offsets to create unions, -fix str() and repr(), allow specifying itemsize, metadata and titles, add flags, -allow subclassing dtype - -.. branch: indexing - -Refactor array indexing to support ellipses. - -.. branch: numpy-docstrings - -Allow the docstrings of built-in numpy objects to be set at run-time. - -.. branch: nditer-revisited - -Implement nditer 'buffered' flag and fix some edge cases - -.. branch: ufunc-reduce - -Allow multiple axes in ufunc.reduce() - -.. branch: fix-tinylang-goals - -Update tinylang goals to match current rpython - -.. branch: vmprof-review - -Clean up of vmprof, notably to handle correctly multiple threads +.. branch: missing_openssl_include +Fix for missing headers in OpenBSD, already applied in downstream ports diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy(pypy_hooks) + #from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy()#pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -9,6 +9,7 @@ implementation for this feature, and patches 'space.threadlocals' when 'thread' is initialized. """ + _immutable_fields_ = ['_value?'] _value = None def get_ec(self): diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -111,7 +111,6 @@ 'interp_magic.mapdict_cache_counter') PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) - # try: from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect() @@ -121,7 +120,7 @@ raise else: pass # ok fine to ignore in this case - # + if self.space.config.translation.jit: features = detect_cpu.getcpufeatures(model) self.extra_interpdef('jit_backend_features', diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -2,7 +2,7 @@ from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib import rdynload -VERSION = "1.2.0" +VERSION = "1.3.0" class Module(MixedModule): diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -19,13 +19,27 @@ # ____________________________________________________________ +class Closure(object): + """This small class is here to have a __del__ outside any cycle.""" + + ll_error = lltype.nullptr(rffi.CCHARP.TO) # set manually + + def __init__(self, ptr): + self.ptr = ptr + + def __del__(self): + clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self.ptr)) + if self.ll_error: + lltype.free(self.ll_error, flavor='raw') + + class W_CDataCallback(W_CData): #_immutable_fields_ = ... - ll_error = lltype.nullptr(rffi.CCHARP.TO) w_onerror = None def __init__(self, space, ctype, w_callable, w_error, w_onerror): raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc()) + self._closure = Closure(raw_closure) W_CData.__init__(self, space, raw_closure, ctype) # if not space.is_true(space.callable(w_callable)): @@ -44,10 +58,11 @@ if size > 0: if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG: size = SIZE_OF_FFI_ARG - self.ll_error = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', - zero=True) + self._closure.ll_error = lltype.malloc(rffi.CCHARP.TO, size, + flavor='raw', zero=True) if not space.is_none(w_error): - convert_from_object_fficallback(fresult, self.ll_error, w_error) + convert_from_object_fficallback(fresult, self._closure.ll_error, + w_error) # self.unique_id = compute_unique_id(self) global_callback_mapping.set(self.unique_id, self) @@ -74,12 +89,6 @@ from pypy.module.thread.os_thread import setup_threads setup_threads(space) - #@rgc.must_be_light_finalizer - def __del__(self): - clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self._ptr)) - if self.ll_error: - lltype.free(self.ll_error, flavor='raw') - def _repr_extra(self): space = self.space return 'calling ' + space.str_w(space.repr(self.w_callable)) @@ -114,8 +123,8 @@ def write_error_return_value(self, ll_res): fresult = self.getfunctype().ctitem if fresult.size > 0: - misc._raw_memcopy(self.ll_error, ll_res, fresult.size) - keepalive_until_here(self) # to keep self.ll_error alive + misc._raw_memcopy(self._closure.ll_error, ll_res, fresult.size) + keepalive_until_here(self) # to keep self._closure.ll_error alive global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback) diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py --- a/pypy/module/_cffi_backend/cffi_opcode.py +++ b/pypy/module/_cffi_backend/cffi_opcode.py @@ -9,16 +9,16 @@ assert isinstance(self.arg, str) return '(_cffi_opcode_t)(%s)' % (self.arg,) classname = CLASS_NAME[self.op] - return '_CFFI_OP(_CFFI_OP_%s, %d)' % (classname, self.arg) + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) def as_python_bytes(self): - if self.op is None: - if self.arg.isdigit(): - value = int(self.arg) # non-negative: '-' not in self.arg - if value >= 2**31: - raise OverflowError("cannot emit %r: limited to 2**31-1" - % (self.arg,)) - return format_four_bytes(value) + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): from .ffiplatform import VerificationError raise VerificationError("cannot emit to Python: %r" % (self.arg,)) return format_four_bytes((self.arg << 8) | self.op) @@ -106,7 +106,9 @@ PRIM_UINTMAX = 47 _NUM_PRIM = 48 -_UNKNOWN_PRIM = -1 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 PRIMITIVE_TO_INDEX = { 'char': PRIM_CHAR, diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -81,6 +81,13 @@ if num == cffi_opcode._UNKNOWN_PRIM: raise oefmt(ffi.w_FFIError, "primitive integer type with an " "unexpected size (or not an integer type at all)") + elif num == cffi_opcode._UNKNOWN_FLOAT_PRIM: + raise oefmt(ffi.w_FFIError, "primitive floating-point type with an " + "unexpected size (or not a float type at all)") + elif num == cffi_opcode._UNKNOWN_LONG_DOUBLE: + raise oefmt(ffi.w_FFIError, "primitive floating-point type is " + "'long double', not supported for now with " + "the syntax 'typedef double... xxx;'") else: raise oefmt(space.w_NotImplementedError, "prim=%d", num) realize_cache = space.fromcache(RealizeCache) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,6 +1,9 @@ # ____________________________________________________________ import sys +assert __version__ == "1.3.0", ("This test_c.py file is for testing a version" + " of cffi that differs from the one that we" + " get from 'import _cffi_backend'") if sys.version_info < (3,): type_or_class = "type" mandatory_b_prefix = '' @@ -3424,7 +3427,3 @@ "be 'foo *', but the types are different (check " "that you are not e.g. mixing up different ffi " "instances)") - -def test_version(): - # this test is here mostly for PyPy - assert __version__ == "1.2.0" diff --git a/pypy/module/_multiprocessing/test/test_memory.py b/pypy/module/_multiprocessing/test/test_memory.py --- a/pypy/module/_multiprocessing/test/test_memory.py +++ b/pypy/module/_multiprocessing/test/test_memory.py @@ -1,8 +1,12 @@ +import sys + class AppTestMemory: spaceconfig = dict(usemodules=('_multiprocessing', 'mmap', '_rawffi', 'itertools', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii')) + if sys.platform != 'win32': + spaceconfig['usemodules'] += ('fcntl',) def test_address_of(self): import _multiprocessing diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py b/pypy/module/_multiprocessing/test/test_semaphore.py --- a/pypy/module/_multiprocessing/test/test_semaphore.py +++ b/pypy/module/_multiprocessing/test/test_semaphore.py @@ -1,12 +1,19 @@ +import sys + from pypy.module._multiprocessing.interp_semaphore import ( RECURSIVE_MUTEX, SEMAPHORE) class AppTestSemaphore: spaceconfig = dict(usemodules=('_multiprocessing', 'thread', - 'signal', 'select', 'fcntl', + 'signal', 'select', 'binascii', 'struct')) + if sys.platform == 'win32': + spaceconfig['usemodules'] += ('_rawffi',) + else: + spaceconfig['usemodules'] += ('fcntl',) + def setup_class(cls): cls.w_SEMAPHORE = cls.space.wrap(SEMAPHORE) cls.w_RECURSIVE = cls.space.wrap(RECURSIVE_MUTEX) diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -379,6 +379,8 @@ PyObject *ht_name, *ht_slots; } PyHeapTypeObject; +#define PyObject_Bytes PyObject_Str + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from rpython.rlib import jit class W_Count(W_Root): @@ -322,6 +323,11 @@ """) +islice_ignore_items_driver = jit.JitDriver(name='islice_ignore_items', + greens=['tp'], + reds=['num', 'w_islice', + 'w_iterator']) + class W_ISlice(W_Root): def __init__(self, space, w_iterable, w_startstop, args_w): self.iterable = space.iter(w_iterable) @@ -407,11 +413,18 @@ raise def _ignore_items(self, num): - if self.iterable is None: + w_iterator = self.iterable + if w_iterator is None: raise OperationError(self.space.w_StopIteration, self.space.w_None) + + tp = self.space.type(w_iterator) while True: + islice_ignore_items_driver.jit_merge_point(tp=tp, + num=num, + w_islice=self, + w_iterator=w_iterator) try: - self.space.next(self.iterable) + self.space.next(w_iterator) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): self.iterable = None diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -1085,3 +1085,18 @@ assert list(itertools.islice(c2, 3)) == expected c3 = pickle.loads(pickle.dumps(c)) assert list(itertools.islice(c3, 3)) == expected + + def test_islice_attack(self): + import itertools + class Iterator(object): + first = True + def __iter__(self): + return self + def next(self): + if self.first: + self.first = False + list(islice) + return 52 + myiter = Iterator() + islice = itertools.islice(myiter, 5, 8) + raises(StopIteration, islice.next) diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,16 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - 'set_compile_hook': 'interp_resop.set_compile_hook', - 'set_optimize_hook': 'interp_resop.set_optimize_hook', - 'set_abort_hook': 'interp_resop.set_abort_hook', - 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - 'enable_debug': 'interp_resop.enable_debug', - 'disable_debug': 'interp_resop.disable_debug', - 'ResOperation': 'interp_resop.WrappedOp', - 'DebugMergePoint': 'interp_resop.DebugMergePoint', - 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - 'Box': 'interp_resop.WrappedBox', + #'set_compile_hook': 'interp_resop.set_compile_hook', + #'set_optimize_hook': 'interp_resop.set_optimize_hook', + #'set_abort_hook': 'interp_resop.set_abort_hook', + #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + #'enable_debug': 'interp_resop.enable_debug', + #'disable_debug': 'interp_resop.disable_debug', + #'ResOperation': 'interp_resop.WrappedOp', + #'DebugMergePoint': 'interp_resop.DebugMergePoint', + #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', + #'Box': 'interp_resop.WrappedBox', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -8,7 +8,7 @@ from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance, hlstr from rpython.rtyper.rclass import OBJECT -from rpython.jit.metainterp.resoperation import rop +#from rpython.jit.metainterp.resoperation import rop from rpython.rlib.nonconst import NonConstant from rpython.rlib import jit_hooks from rpython.rlib.jit import Counters diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -326,7 +326,7 @@ # to repeat it every time ticker_check = """ guard_not_invalidated? - ticker0 = getfield_raw(#, descr=) + ticker0 = getfield_raw_i(#, descr=) ticker_cond0 = int_lt(ticker0, 0) guard_false(ticker_cond0, descr=...) """ @@ -335,7 +335,7 @@ # this is the ticker check generated if we have threads thread_ticker_check = """ guard_not_invalidated? - ticker0 = getfield_raw(#, descr=) + ticker0 = getfield_raw_i(#, descr=) ticker1 = int_sub(ticker0, #) setfield_raw(#, ticker1, descr=) ticker_cond0 = int_lt(ticker1, 0) @@ -345,7 +345,7 @@ # # this is the ticker check generated in PyFrame.handle_operation_error exc_ticker_check = """ - ticker2 = getfield_raw(#, descr=) + ticker2 = getfield_raw_i(#, descr=) ticker_cond1 = int_lt(ticker2, 0) guard_false(ticker_cond1, descr=...) """ diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -76,7 +76,7 @@ stdout = stdout.splitlines(True)[-1] # # parse the JIT log - rawlog = logparser.parse_log_file(str(logfile)) + rawlog = logparser.parse_log_file(str(logfile), verbose=False) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) @@ -471,7 +471,7 @@ # this is the actual loop 'int_lt', 'guard_true', 'int_add', # this is the signal checking stuff - 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false', + 'guard_not_invalidated', 'getfield_raw_i', 'int_lt', 'guard_false', 'jump' ] @@ -536,7 +536,7 @@ # this is the actual loop 'int_lt', 'guard_true', 'force_token', 'int_add', # this is the signal checking stuff - 'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false', + 'guard_not_invalidated', 'getfield_raw_i', 'int_lt', 'guard_false', 'jump' ] @@ -555,7 +555,7 @@ i8 = int_add(i4, 1) # signal checking stuff guard_not_invalidated(descr=...) - i10 = getfield_raw(..., descr=<.* pypysig_long_struct.c_value .*>) + i10 = getfield_raw_i(..., descr=<.* pypysig_long_struct.c_value .*>) i14 = int_lt(i10, 0) guard_false(i14, descr=...) jump(..., descr=...) @@ -609,13 +609,13 @@ log = self.run(f, import_site=True) loop, = log.loops_by_id('ntohs') assert loop.match_by_id('ntohs', """ - p12 = call(ConstClass(ntohs), 1, descr=...) + i12 = call_i(ConstClass(ntohs), 1, descr=...) guard_no_exception(descr=...) """, include_guard_not_invalidated=False) # py.test.raises(InvalidMatch, loop.match_by_id, 'ntohs', """ guard_not_invalidated(descr=...) - p12 = call(ConstClass(foobar), 1, descr=...) + i12 = call_i(ConstClass(foobar), 1, descr=...) guard_no_exception(descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -42,7 +42,7 @@ guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) - i15 = getarrayitem_raw(i10, i7, descr=) + i15 = getarrayitem_raw_i(i10, i7, descr=) i16 = int_add_ovf(i8, i15) guard_no_overflow(descr=...) i18 = int_add(i7, 1) @@ -74,12 +74,12 @@ guard_true(i13, descr=...) guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=) + i14 = getarrayitem_raw_i(i10, i8, descr=) i15 = int_add_ovf(i9, i14) guard_no_overflow(descr=...) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=) + i18 = getarrayitem_raw_i(i11, i17, descr=) i19 = int_add_ovf(i18, i15) guard_no_overflow(descr=...) setarrayitem_raw(i11, i8, _, descr=) @@ -93,7 +93,7 @@ guard_true(i13, descr=...) guard_not_invalidated(descr=...) # the bound check guard on img has been killed (thanks to the asserts) - i14 = getarrayitem_raw(i10, i8, descr=) + i14 = getarrayitem_raw_i(i10, i8, descr=) # advanced: the following int_add cannot overflow, because: # - i14 fits inside 32 bits # - i9 fits inside 33 bits, because: @@ -107,7 +107,7 @@ i15 = int_add(i9, i14) i17 = int_sub(i8, 640) # the bound check guard on intimg has been killed (thanks to the asserts) - i18 = getarrayitem_raw(i11, i17, descr=) + i18 = getarrayitem_raw_i(i11, i17, descr=) i19 = int_add(i18, i15) # guard checking that i19 actually fits into 32bit i20 = int_signext(i19, 4) @@ -139,10 +139,10 @@ guard_true(i10, descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) - f13 = getarrayitem_raw(i8, i6, descr=) + f13 = getarrayitem_raw_f(i8, i6, descr=) f15 = float_add(f13, 20.500000) setarrayitem_raw(i8, i6, f15, descr=) - f16 = getarrayitem_raw(i8, i6, descr=) + f16 = getarrayitem_raw_f(i8, i6, descr=) i18 = float_eq(f16, 42.000000) guard_true(i18, descr=...) i20 = int_add(i6, 1) @@ -175,12 +175,12 @@ guard_true(i10, descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) - i13 = getarrayitem_raw(i8, i6, descr=) + i13 = getarrayitem_raw_i(i8, i6, descr=) f14 = cast_singlefloat_to_float(i13) f16 = float_add(f14, 20.500000) i17 = cast_float_to_singlefloat(f16) setarrayitem_raw(i8, i6,i17, descr=) - i18 = getarrayitem_raw(i8, i6, descr=) + i18 = getarrayitem_raw_i(i8, i6, descr=) f19 = cast_singlefloat_to_float(i18) i21 = float_eq(f19, 42.000000) guard_true(i21, descr=...) @@ -225,23 +225,23 @@ ... i20 = int_ge(i18, i8) guard_false(i20, descr=...) - f21 = getarrayitem_raw(i13, i18, descr=...) + f21 = getarrayitem_raw_f(i13, i18, descr=...) i14 = int_sub(i6, 1) i15 = int_ge(i14, i8) guard_false(i15, descr=...) - f23 = getarrayitem_raw(i13, i14, descr=...) + f23 = getarrayitem_raw_f(i13, i14, descr=...) f24 = float_add(f21, f23) - f26 = getarrayitem_raw(i13, i6, descr=...) + f26 = getarrayitem_raw_f(i13, i6, descr=...) f27 = float_add(f24, f26) i29 = int_add(i6, 1) i31 = int_ge(i29, i8) guard_false(i31, descr=...) - f33 = getarrayitem_raw(i13, i29, descr=...) + f33 = getarrayitem_raw_f(i13, i29, descr=...) f34 = float_add(f27, f33) i36 = int_add(i6, 2) i38 = int_ge(i36, i8) guard_false(i38, descr=...) - f39 = getarrayitem_raw(i13, i36, descr=...) + f39 = getarrayitem_raw_f(i13, i36, descr=...) ... """) @@ -276,20 +276,20 @@ expected_src=""" ... i17 = int_and(i14, 255) - f18 = getarrayitem_raw(i8, i17, descr=...) + f18 = getarrayitem_raw_f(i8, i17, descr=...) i19s = int_sub_ovf(i6, 1) guard_no_overflow(descr=...) i22s = int_and(i19s, 255) - f20 = getarrayitem_raw(i8, i22s, descr=...) + f20 = getarrayitem_raw_f(i8, i22s, descr=...) f21 = float_add(f18, f20) - f23 = getarrayitem_raw(i8, i10, descr=...) + f23 = getarrayitem_raw_f(i8, i10, descr=...) f24 = float_add(f21, f23) i26 = int_add(i6, 1) i29 = int_and(i26, 255) - f30 = getarrayitem_raw(i8, i29, descr=...) + f30 = getarrayitem_raw_f(i8, i29, descr=...) f31 = float_add(f24, f30) i33 = int_add(i6, 2) i36 = int_and(i33, 255) - f37 = getarrayitem_raw(i8, i36, descr=...) + f37 = getarrayitem_raw_f(i8, i36, descr=...) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_buffers.py b/pypy/module/pypyjit/test_pypy_c/test_buffers.py --- a/pypy/module/pypyjit/test_pypy_c/test_buffers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_buffers.py @@ -18,7 +18,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('match', """ guard_not_invalidated(descr=...) - i65 = getfield_gc(p18, descr=...) + i65 = getfield_gc_i(p18, descr=...) i67 = int_gt(0, i65) guard_false(i67, descr=...) i69 = int_gt(#, i65) @@ -42,7 +42,7 @@ assert loop.match_by_id('unpack', """ guard_not_invalidated(descr=...) p90 = newstr(4) - call(ConstClass(copy_raw_to_string), i55, p90, 0, 4, descr=) + call_n(ConstClass(copy_raw_to_string), i55, p90, 0, 4, descr=) guard_no_exception(descr=...) i91 = strgetitem(p90, 0) i92 = strgetitem(p90, 1) @@ -56,7 +56,7 @@ guard_false(i99, descr=...) i100 = int_lshift(i98, 24) i101 = int_or(i97, i100) - i102 = getfield_raw(#, descr=) + i102 = getfield_raw_i(#, descr=) i103 = int_lt(i102, 0) guard_false(i103, descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -31,7 +31,7 @@ functrace, loop = log.loops_by_filename(self.filepath) assert loop.match_by_id('call_rec', """ ... - p53 = call_assembler(..., descr=...) + p53 = call_assembler_r(..., descr=...) guard_not_forced(descr=...) keepalive(...) guard_no_exception(descr=...) @@ -73,7 +73,7 @@ ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", "guard_value", - "getfield_gc", "guard_value", + "getfield_gc_r", "guard_value", "guard_not_invalidated"] ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') assert log.opnames(ops) == [] @@ -82,12 +82,12 @@ assert log.opnames(ops) == [] # assert entry_bridge.match_by_id('call', """ - p38 = call(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) - p39 = getfield_gc(p38, descr=) + p38 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) + p39 = getfield_gc_r(p38, descr=) i40 = force_token() - p41 = getfield_gc_pure(p38, descr=) + p41 = getfield_gc_pure_r(p38, descr=) guard_value(p41, ConstPtr(ptr42), descr=...) - i42 = getfield_gc_pure(p38, descr=) + i42 = getfield_gc_pure_i(p38, descr=) i43 = int_is_zero(i42) guard_true(i43, descr=...) i50 = force_token() @@ -130,7 +130,8 @@ # ------------------------------- entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('meth1', opcode='LOOKUP_METHOD') - assert log.opnames(ops) == ['guard_value', 'getfield_gc', 'guard_value', + assert log.opnames(ops) == ['guard_value', 'getfield_gc_r', + 'guard_value', 'guard_not_invalidated'] # the second LOOKUP_METHOD is folded away assert list(entry_bridge.ops_by_id('meth2', opcode='LOOKUP_METHOD')) == [] @@ -349,15 +350,13 @@ # the int strategy is used here assert loop.match_by_id('append', """ guard_not_invalidated? - i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) - p15 = getfield_gc(p8, descr=) i17 = arraylen_gc(p15, descr=) i18 = int_lt(i17, i15) # a cond call to _ll_list_resize_hint_really_look_inside_iff cond_call(i18, _, p8, i15, 1, descr=) guard_no_exception(descr=...) - p17 = getfield_gc(p8, descr=) + p17 = getfield_gc_r(p8, descr=) setarrayitem_gc(p17, i13, i12, descr=) """) @@ -381,9 +380,9 @@ # make sure that the "block" is not allocated ... p20 = force_token() - p22 = new_with_vtable(...) + p22 = new_with_vtable(descr=) p24 = new_array_clear(1, descr=) - p26 = new_with_vtable(ConstClass(W_ListObject)) + p26 = new_with_vtable(descr=) {{{ setfield_gc(p0, p20, descr=) setfield_gc(p22, ConstPtr(null), descr=) @@ -395,7 +394,7 @@ setarrayitem_gc(p24, 0, p26, descr=) setfield_gc(p22, p24, descr=) }}} - p32 = call_may_force(_, p18, p22, descr=) + p32 = call_may_force_r(_, p18, p22, descr=) ... """) @@ -436,24 +435,24 @@ guard_isnull(p5, descr=...) guard_nonnull_class(p12, ConstClass(W_IntObject), descr=...) guard_value(p2, ConstPtr(ptr21), descr=...) - i22 = getfield_gc_pure(p12, descr=) + i22 = getfield_gc_pure_i(p12, descr=) i24 = int_lt(i22, 5000) guard_true(i24, descr=...) guard_value(p7, ConstPtr(ptr25), descr=...) - p26 = getfield_gc(p7, descr=) + p26 = getfield_gc_r(p7, descr=) guard_value(p26, ConstPtr(ptr27), descr=...) guard_not_invalidated(descr=...) - p29 = call(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) - p30 = getfield_gc(p29, descr=) + p29 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=) + p30 = getfield_gc_r(p29, descr=) p31 = force_token() - p32 = getfield_gc_pure(p29, descr=) + p32 = getfield_gc_pure_r(p29, descr=) guard_value(p32, ConstPtr(ptr33), descr=...) - i34 = getfield_gc_pure(p29, descr=) + i34 = getfield_gc_pure_i(p29, descr=) i35 = int_is_zero(i34) guard_true(i35, descr=...) - p37 = getfield_gc(ConstPtr(ptr36), descr=) + p37 = getfield_gc_r(ConstPtr(ptr36), descr=) guard_nonnull_class(p37, ConstClass(W_IntObject), descr=...) - i39 = getfield_gc_pure(p37, descr=) + i39 = getfield_gc_pure_i(p37, descr=) i40 = int_add_ovf(i22, i39) guard_no_overflow(descr=...) --TICK-- @@ -470,13 +469,13 @@ """, []) loop, = log.loops_by_id('call') assert loop.match(""" - i8 = getfield_gc_pure(p6, descr=) + i8 = getfield_gc_pure_i(p6, descr=) i10 = int_lt(i8, 5000) guard_true(i10, descr=...) i11 = force_token() i13 = int_add(i8, 1) --TICK-- - p22 = new_with_vtable(ConstClass(W_IntObject)) + p22 = new_with_vtable(descr=) setfield_gc(p22, i13, descr=) setfield_gc(p4, p22, descr=) jump(..., descr=...) @@ -576,8 +575,8 @@ allops = loop.allops() calls = [op for op in allops if op.name.startswith('call')] assert OpMatcher(calls).match(''' - p93 = call(ConstClass(view_as_kwargs), p35, p12, descr=<.*>) - i103 = call(ConstClass(_match_keywords), ConstPtr(ptr52), 0, 0, p94, p98, 0, descr=<.*>) + p93 = call_r(ConstClass(view_as_kwargs), p35, p12, descr=<.*>) + i103 = call_i(ConstClass(_match_keywords), ConstPtr(ptr52), 0, 0, p94, p98, 0, descr=<.*>) ''') assert len([op for op in allops if op.name.startswith('new')]) == 1 # 1 alloc diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -43,9 +43,9 @@ # can't change ;) assert loop.match_by_id("getitem", """ ... - i26 = call(ConstClass(ll_call_lookup_function), p18, p6, i25, 0, descr=...) + i26 = call_i(ConstClass(ll_call_lookup_function), p18, p6, i25, 0, descr=...) ... - p33 = getinteriorfield_gc(p31, i26, descr=>) + p33 = getinteriorfield_gc_r(p31, i26, descr=>) ... """) @@ -64,9 +64,9 @@ i8 = int_lt(i5, i7) guard_true(i8, descr=...) guard_not_invalidated(descr=...) - p10 = call(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) + p10 = call_r(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) guard_no_exception(descr=...) - i12 = call(ConstClass(ll_strhash), p10, descr=) + i12 = call_i(ConstClass(ll_strhash), p10, descr=) p13 = new(descr=...) p15 = new_array_clear(16, descr=) {{{ @@ -74,25 +74,25 @@ setfield_gc(p13, p15, descr=) setfield_gc(p13, ConstPtr(0), descr=) }}} - i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) + i17 = call_i(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) {{{ setfield_gc(p13, 0, descr=) setfield_gc(p13, 0, descr=) setfield_gc(p13, 32, descr=) }}} guard_no_exception(descr=...) - p20 = new_with_vtable(ConstClass(W_IntObject)) - call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) + p20 = new_with_vtable(descr=...) + call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) setfield_gc(p20, i5, descr=) guard_no_exception(descr=...) - i23 = call(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) + i23 = call_i(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) guard_no_exception(descr=...) i27 = int_lt(i23, 0) guard_false(i27, descr=...) - p28 = getfield_gc(p13, descr=) - p29 = getinteriorfield_gc(p28, i23, descr=>) + p28 = getfield_gc_r(p13, descr=) + p29 = getinteriorfield_gc_r(p28, i23, descr=>) guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...) - i31 = getfield_gc_pure(p29, descr=) + i31 = getfield_gc_pure_i(p29, descr=) i32 = int_sub_ovf(i31, i5) guard_no_overflow(descr=...) i34 = int_add_ovf(i32, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py --- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py +++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py @@ -31,7 +31,7 @@ # but all calls can be special-cased by the backend if # supported. On 64-bit there is only the two calls to # read_timestamp. - r = re.compile(r" call[(]ConstClass[(](.+?)[)]") + r = re.compile(r" call_\w[(]ConstClass[(](.+?)[)]") calls = r.findall(repr(loop.ops_by_id(method))) if sys.maxint == 2147483647: assert len(calls) == 6 diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -163,7 +163,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id('getfield', """ guard_not_invalidated(descr=...) - i57 = getfield_raw(i46, descr=) + i57 = getfield_raw_i(i46, descr=) """) assert loop.match_by_id('setfield', """ setfield_raw(i44, i57, descr=) @@ -202,7 +202,7 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - f97 = call_release_gil(91, i59, 1.0, 3, descr=) + f97 = call_release_gil_f(91, i59, 1.0, 3, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) """, ignore_ops=['guard_not_invalidated']) @@ -244,7 +244,7 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - i97 = call_release_gil(91, i59, i50, descr=) + i97 = call_release_gil_i(91, i59, i50, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) %s @@ -288,10 +288,10 @@ assert loop.match_by_id('cfficall', """ p96 = force_token() setfield_gc(p0, p96, descr=) - i97 = call_release_gil(91, i59, i10, i12, 1, descr=) + i97 = call_release_gil_i(91, i59, i10, i12, 1, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) - p98 = call(ConstClass(fromrarith_int__r_uint), i97, descr=) + p98 = call_r(ConstClass(fromrarith_int__r_uint), i97, descr=) guard_no_exception(descr=...) """, ignore_ops=['guard_not_invalidated']) @@ -354,7 +354,7 @@ loop, = log.loops_by_id('cfficall') assert loop.match_by_id('cfficall', """ ... - f1 = call_release_gil(..., descr=) + i1 = call_release_gil_i(..., descr=) ... """) @@ -414,11 +414,7 @@ guard_not_invalidated(descr=...) p163 = force_token() p164 = force_token() - p165 = getarrayitem_gc(p67, 0, descr=) - guard_value(p165, ConstPtr(ptr70), descr=...) - p166 = getfield_gc(p165, descr=) - guard_value(p166, ConstPtr(ptr72), descr=...) - p167 = call(ConstClass(_ll_0_alloc_with_del___), descr=) + p167 = call_r(ConstClass(_ll_0_alloc_with_del___), descr=) guard_no_exception(descr=...) i112 = int_signext(i160, 2) setfield_gc(p167, ConstPtr(ptr85), descr=) @@ -426,7 +422,7 @@ i114 = int_ne(i160, i112) guard_false(i114, descr=...) --TICK-- - i119 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) + i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py --- a/pypy/module/pypyjit/test_pypy_c/test_generators.py +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -21,10 +21,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + ifoo = arraylen_gc(p8, descr=) setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ @@ -50,10 +50,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + i47 = arraylen_gc(p8, descr=) # Should be removed by backend setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py --- a/pypy/module/pypyjit/test_pypy_c/test_globals.py +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -16,9 +16,9 @@ assert log.result == 500 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id("loadglobal", """ - p12 = getfield_gc(p10, descr=) + p12 = getfield_gc_r(p10, descr=) guard_value(p12, ConstPtr(ptr13), descr=...) guard_not_invalidated(descr=...) - p19 = getfield_gc(ConstPtr(p17), descr=) + p19 = getfield_gc_r(ConstPtr(p17), descr=) guard_value(p19, ConstPtr(ptr20), descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -106,7 +106,7 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc'] + 'getfield_gc_i'] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] # @@ -120,11 +120,11 @@ i59 = int_add_ovf(i57, 1) guard_no_overflow(descr=...) p60 = force_token() - i61 = getfield_raw(..., descr=...) + i61 = getfield_raw_i(..., descr=...) setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) - jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...) + jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, p100, descr=...) """) def test_mutate_class(self): @@ -154,8 +154,8 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class', - 'getfield_gc', 'guard_value', # type check on the attribute + 'getfield_gc_r', 'guard_nonnull_class', + 'getfield_gc_r', 'guard_value', # type check on the attribute ] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] @@ -167,15 +167,15 @@ i70 = int_lt(i58, i33) guard_true(i70, descr=...) guard_not_invalidated(descr=...) - p71 = getfield_gc(p64, descr=...) + p71 = getfield_gc_r(p64, descr=...) guard_value(p71, ConstPtr(ptr42), descr=...) p72 = force_token() p73 = force_token() i74 = int_add(i58, 1) - i75 = getfield_raw(..., descr=...) + i75 = getfield_raw_i(..., descr=...) i76 = int_lt(i75, 0) guard_false(i76, descr=...) - p77 = new_with_vtable(...) + p77 = new_with_vtable(descr=...) setfield_gc(p77, p64, descr=...) setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(null), descr=...) @@ -183,7 +183,7 @@ setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(ptr42), descr=...) setfield_gc(ConstPtr(ptr69), p77, descr=...) - jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...) + jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, p100, descr=...) """) @@ -209,11 +209,11 @@ assert loop.match_by_id('loadattr1', ''' guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i19 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i22 = int_lt(i19, 0) guard_true(i22, descr=...) - i26 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i26 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i29 = int_lt(i26, 0) guard_true(i29, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -23,8 +23,8 @@ f1 = cast_int_to_float(i0) i3 = float_le(f1, 0.0) guard_false(i3, descr=...) - f2 = call(ConstClass(log), f1, descr=) - f3 = call(ConstClass(log10), f1, descr=) + f2 = call_f(ConstClass(log), f1, descr=) + f3 = call_f(ConstClass(log10), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i4 = int_add(i0, 1) @@ -52,8 +52,8 @@ f1 = cast_int_to_float(i0) i6 = --ISINF--(f1) guard_false(i6, descr=...) - f2 = call(ConstClass(sin), f1, descr=) - f3 = call(ConstClass(cos), f1, descr=) + f2 = call_f(ConstClass(sin), f1, descr=) + f3 = call_f(ConstClass(cos), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i7 = int_add(i0, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -15,36 +15,36 @@ loop = log._filter(log.loops[0]) assert loop.match(""" guard_class(p1, #, descr=...) - p4 = getfield_gc_pure(p1, descr=) - i5 = getfield_gc(p0, descr=) - p6 = getfield_gc_pure(p4, descr=) - p7 = getfield_gc_pure(p6, descr=) + p4 = getfield_gc_pure_r(p1, descr=) + i5 = getfield_gc_i(p0, descr=) + p6 = getfield_gc_pure_r(p4, descr=) + p7 = getfield_gc_pure_r(p6, descr=) guard_class(p7, ConstClass(Float64), descr=...) - i9 = getfield_gc_pure(p4, descr=) - i10 = getfield_gc_pure(p6, descr=) + i9 = getfield_gc_pure_i(p4, descr=) + i10 = getfield_gc_pure_i(p6, descr=) i12 = int_eq(i10, 61) i14 = int_eq(i10, 60) i15 = int_or(i12, i14) - f16 = raw_load(i9, i5, descr=) + f16 = raw_load_f(i9, i5, descr=) guard_true(i15, descr=...) guard_not_invalidated(descr=...) i18 = float_ne(f16, 0.000000) guard_true(i18, descr=...) guard_nonnull_class(p2, ConstClass(W_BoolBox), descr=...) - i20 = getfield_gc_pure(p2, descr=) + i20 = getfield_gc_pure_i(p2, descr=) i21 = int_is_true(i20) guard_false(i21, descr=...) - i22 = getfield_gc(p0, descr=) - i23 = getfield_gc_pure(p1, descr=) + i22 = getfield_gc_i(p0, descr=) + i23 = getfield_gc_pure_i(p1, descr=) guard_true(i23, descr=...) i25 = int_add(i22, 1) - p26 = getfield_gc_pure(p0, descr=) - i27 = getfield_gc_pure(p1, descr=) + p26 = getfield_gc_pure_r(p0, descr=) + i27 = getfield_gc_pure_i(p1, descr=) i28 = int_is_true(i27) guard_true(i28, descr=...) - i29 = getfield_gc_pure(p6, descr=) + i29 = getfield_gc_pure_i(p6, descr=) i30 = int_add(i5, i29) - i31 = getfield_gc_pure(p1, descr=) + i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) p34 = new_with_vtable(#) @@ -68,13 +68,13 @@ assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - f31 = raw_load(i9, i29, descr=) + f31 = raw_load_f(i9, i29, descr=) guard_not_invalidated(descr=...) i32 = float_ne(f31, 0.000000) guard_true(i32, descr=...) - i34 = getarrayitem_raw(#, #, descr=) # XXX what are these? + i34 = getarrayitem_raw_i(#, #, descr=) # XXX what are these? guard_value(i34, #, descr=...) # XXX don't appear in - i35 = getarrayitem_raw(#, #, descr=) # XXX equiv test_zjit + i35 = getarrayitem_raw_i(#, #, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, i28) i38 = int_ge(i36, i30) @@ -112,7 +112,7 @@ i78 = int_mul(i71, i61) i79 = int_add(i55, i78) """ + alignment_check + """ - f80 = raw_load(i67, i79, descr=) + f80 = raw_load_f(i67, i79, descr=) i81 = int_add(i71, 1) --TICK-- jump(..., descr=...) @@ -149,7 +149,7 @@ i83 = int_mul(i76, i64) i84 = int_add(i58, i83) """ + alignment_check + """ - f85 = raw_load(i70, i84, descr=) + f85 = raw_load_f(i70, i84, descr=) guard_not_invalidated(descr=...) f86 = float_add(f74, f85) i87 = int_add(i76, 1) @@ -176,11 +176,11 @@ guard_not_invalidated(descr=...) i88 = int_ge(i87, i59) guard_false(i88, descr=...) - f90 = raw_load(i67, i89, descr=) + f90 = raw_load_f(i67, i89, descr=) i91 = int_add(i87, 1) i93 = int_add(i89, i76) i94 = int_add(i79, 1) - i95 = getfield_raw(#, descr=) + i95 = getfield_raw_i(#, descr=) setfield_gc(p97, i91, descr=) setfield_gc(p97, i93, descr=) i96 = int_lt(i95, 0) @@ -208,11 +208,11 @@ guard_true(i126, descr=...) i128 = int_mul(i117, i59) i129 = int_add(i55, i128) - f149 = raw_load(i100, i129, descr=) + f149 = raw_load_f(i100, i129, descr=) i151 = int_add(i117, 1) + setfield_gc(p156, i55, descr=) setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) - setfield_gc(p156, i55, descr=) --TICK-- jump(..., descr=...) """) @@ -240,10 +240,10 @@ guard_not_invalidated(descr=...) From noreply at buildbot.pypy.org Wed Sep 16 23:39:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 16 Sep 2015 23:39:50 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150916213950.9C0D41C0933@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r637:e3f066d31bc0 Date: 2015-09-16 23:40 +0200 http://bitbucket.org/pypy/pypy.org/changeset/e3f066d31bc0/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -9,13 +9,13 @@ - $60308 of $105000 (57.4%) + $60498 of $105000 (57.6%)
    @@ -23,7 +23,7 @@
  • From noreply at buildbot.pypy.org Thu Sep 17 10:56:08 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 17 Sep 2015 10:56:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Get rid of an 'align_stack' boolean argument by calling Message-ID: <20150917085608.E92CA1C043B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79660:4a7854aaae79 Date: 2015-09-17 10:56 +0200 http://bitbucket.org/pypy/pypy/changeset/4a7854aaae79/ Log: Get rid of an 'align_stack' boolean argument by calling _reload_frame_if_necessary() earlier. Might fix a very rare problem if the malloc slowpath returns NULL (out of memory) but the jitframe moved. diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -175,12 +175,12 @@ for i in range(4): mc.MOV_sr(i * WORD, cond_call_register_arguments[i].value) mc.CALL(eax) + self._reload_frame_if_necessary(mc) if IS_X86_64: mc.ADD(esp, imm(WORD)) else: mc.ADD(esp, imm(WORD * 7)) self.set_extra_stack_depth(mc, 0) - self._reload_frame_if_necessary(mc, align_stack=True) self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only) mc.RET() @@ -244,14 +244,15 @@ mc.MOV_rs(edi.value, WORD * 3) # load the itemsize self.set_extra_stack_depth(mc, 16) mc.CALL(imm(follow_jump(addr))) + self._reload_frame_if_necessary(mc) mc.ADD_ri(esp.value, 16 - WORD) + self.set_extra_stack_depth(mc, 0) + # mc.TEST_rr(eax.value, eax.value) mc.J_il(rx86.Conditions['Z'], 0xfffff) # patched later jz_location = mc.get_relative_pos() # nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr() - self._reload_frame_if_necessary(mc, align_stack=True) - self.set_extra_stack_depth(mc, 0) self._pop_all_regs_from_frame(mc, [eax, edi], self.cpu.supports_floats) mc.MOV(edi, heap(nursery_free_adr)) # load this in EDI self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller @@ -1050,8 +1051,7 @@ cb = callbuilder.CallBuilder(self, fnloc, arglocs) cb.emit_no_collect() - def _reload_frame_if_necessary(self, mc, align_stack=False, - shadowstack_reg=None): + def _reload_frame_if_necessary(self, mc, shadowstack_reg=None): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: if gcrootmap.is_shadow_stack: @@ -1065,7 +1065,7 @@ # frame never uses card marking, so we enforce this is not # an array self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, - is_frame=True, align_stack=align_stack) + is_frame=True) genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") @@ -2083,7 +2083,7 @@ # ------------------- END CALL ASSEMBLER ----------------------- def _write_barrier_fastpath(self, mc, descr, arglocs, array=False, - is_frame=False, align_stack=False): + is_frame=False): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls a # helper piece of assembler. The latter saves registers as needed @@ -2139,13 +2139,9 @@ # if not is_frame: mc.PUSH(loc_base) - if is_frame and align_stack: - mc.SUB_ri(esp.value, 16 - WORD) # erase the return address mc.CALL(imm(self.wb_slowpath[helper_num])) if not is_frame: mc.stack_frame_size_delta(-WORD) - if is_frame and align_stack: - mc.ADD_ri(esp.value, 16 - WORD) # erase the return address if card_marking: # The helper ends again with a check of the flag in the object. From noreply at buildbot.pypy.org Thu Sep 17 11:27:52 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 11:27:52 +0200 (CEST) Subject: [pypy-commit] pypy default: uh, how the hell did it compile at all kind of commit Message-ID: <20150917092752.AA39D1C0148@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79661:c8e39fddd4a1 Date: 2015-09-17 11:27 +0200 http://bitbucket.org/pypy/pypy/changeset/c8e39fddd4a1/ Log: uh, how the hell did it compile at all kind of commit diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -2,7 +2,7 @@ from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib.debug import debug_start, debug_stop, debug_print +from rpython.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib import rstack from rpython.rlib.jit import JitDebugInfo, Counters, dont_look_inside @@ -531,6 +531,7 @@ loop.inputargs, operations, original_jitcell_token, name=loopname, + log=have_debug_prints(), memo=memo) finally: debug_stop("jit-backend") @@ -577,7 +578,8 @@ try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, - original_loop_token, memo) + original_loop_token, have_debug_prints(), + memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() From noreply at buildbot.pypy.org Thu Sep 17 11:28:40 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 11:28:40 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: merge default Message-ID: <20150917092840.12B0F1C0148@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79662:afcfd65aebea Date: 2015-09-17 11:28 +0200 http://bitbucket.org/pypy/pypy/changeset/afcfd65aebea/ Log: merge default diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from rpython.rlib import jit class W_Count(W_Root): @@ -322,6 +323,11 @@ """) +islice_ignore_items_driver = jit.JitDriver(name='islice_ignore_items', + greens=['tp'], + reds=['num', 'w_islice', + 'w_iterator']) + class W_ISlice(W_Root): def __init__(self, space, w_iterable, w_startstop, args_w): self.iterable = space.iter(w_iterable) @@ -407,11 +413,18 @@ raise def _ignore_items(self, num): - if self.iterable is None: + w_iterator = self.iterable + if w_iterator is None: raise OperationError(self.space.w_StopIteration, self.space.w_None) + + tp = self.space.type(w_iterator) while True: + islice_ignore_items_driver.jit_merge_point(tp=tp, + num=num, + w_islice=self, + w_iterator=w_iterator) try: - self.space.next(self.iterable) + self.space.next(w_iterator) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): self.iterable = None diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -1085,3 +1085,18 @@ assert list(itertools.islice(c2, 3)) == expected c3 = pickle.loads(pickle.dumps(c)) assert list(itertools.islice(c3, 3)) == expected + + def test_islice_attack(self): + import itertools + class Iterator(object): + first = True + def __iter__(self): + return self + def next(self): + if self.first: + self.first = False + list(islice) + return 52 + myiter = Iterator() + islice = itertools.islice(myiter, 5, 8) + raises(StopIteration, islice.next) diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -81,7 +81,7 @@ setfield_gc(p13, 32, descr=) }}} guard_no_exception(descr=...) - p20 = new_with_vtable(ConstClass(W_IntObject)) + p20 = new_with_vtable(descr=...) call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) setfield_gc(p20, i5, descr=) guard_no_exception(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py --- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py +++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py @@ -31,7 +31,7 @@ # but all calls can be special-cased by the backend if # supported. On 64-bit there is only the two calls to # read_timestamp. - r = re.compile(r" call[(]ConstClass[(](.+?)[)]") + r = re.compile(r" call_\w[(]ConstClass[(](.+?)[)]") calls = r.findall(repr(loop.ops_by_id(method))) if sys.maxint == 2147483647: assert len(calls) == 6 diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -124,7 +124,7 @@ setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) - jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...) + jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, p100, descr=...) """) def test_mutate_class(self): @@ -167,7 +167,7 @@ i70 = int_lt(i58, i33) guard_true(i70, descr=...) guard_not_invalidated(descr=...) - p71 = getfield_gc(p64, descr=...) + p71 = getfield_gc_r(p64, descr=...) guard_value(p71, ConstPtr(ptr42), descr=...) p72 = force_token() p73 = force_token() @@ -175,7 +175,7 @@ i75 = getfield_raw_i(..., descr=...) i76 = int_lt(i75, 0) guard_false(i76, descr=...) - p77 = new_with_vtable(...) + p77 = new_with_vtable(descr=...) setfield_gc(p77, p64, descr=...) setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(null), descr=...) @@ -183,7 +183,7 @@ setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(ptr42), descr=...) setfield_gc(ConstPtr(ptr69), p77, descr=...) - jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...) + jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, p100, descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -38,7 +38,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) loop2 = log.loops[0] @@ -50,11 +50,11 @@ guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) - p18 = getarrayitem_gc(p5, i11, descr=...) + p18 = getarrayitem_gc_r(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) - i20 = getfield_gc_pure(p18, descr=...) + i20 = getfield_gc_pure_i(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) @@ -79,6 +79,6 @@ assert len(guards) < 20 assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -65,7 +65,7 @@ assert loop.match(""" i7 = int_gt(i4, 1) guard_true(i7, descr=...) - p11 = call(ConstClass(rbigint.int_mul), p5, i4, descr=...) + p11 = call_r(ConstClass(rbigint.int_mul), p5, i4, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) --TICK-- @@ -113,14 +113,14 @@ i12 = int_is_true(i4) guard_true(i12, descr=...) guard_not_invalidated(descr=...) - i13 = int_add_ovf(i8, i9) - guard_no_overflow(descr=...) - i10p = getfield_gc_pure(p10, descr=...) + i10p = getfield_gc_pure_i(p10, descr=...) i10 = int_mul_ovf(2, i10p) guard_no_overflow(descr=...) i14 = int_add_ovf(i13, i10) guard_no_overflow(descr=...) - setfield_gc(p7, p11, descr=...) + i13 = int_add_ovf(i14, i9) + guard_no_overflow(descr=...) + setfield_gc(p17, p10, descr=...) i17 = int_sub_ovf(i4, 1) guard_no_overflow(descr=...) --TICK-- @@ -277,6 +277,7 @@ i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=...) --TICK-- + if00 = arraylen_gc(p16, descr=...) jump(..., descr=...) """) diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -131,7 +131,7 @@ def _record_constptrs(self, op, gcrefs_output_list, ops_with_movable_const_ptr, changeable_const_pointers): - ops_with_movable_const_ptr[op] = [] + l = None for i in range(op.numargs()): v = op.getarg(i) if isinstance(v, ConstPtr) and bool(v.value): @@ -139,7 +139,10 @@ if rgc._make_sure_does_not_move(p): gcrefs_output_list.append(p) else: - ops_with_movable_const_ptr[op].append(i) + if l is None: + l = [i] + else: + l.append(i) if v not in changeable_const_pointers: changeable_const_pointers.append(v) # @@ -148,8 +151,8 @@ assert rgc._make_sure_does_not_move(llref) gcrefs_output_list.append(llref) # - if len(ops_with_movable_const_ptr[op]) == 0: - del ops_with_movable_const_ptr[op] + if l: + ops_with_movable_const_ptr[op] = l def _rewrite_changeable_constptrs(self, op, ops_with_movable_const_ptr, moving_obj_tracker): newops = [] diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2601,16 +2601,16 @@ # call: 8 bytes too much. If we repeat the call often enough, crash. ops = [] for i in range(50): - i3 = InputArgInt() ops += [ - ResOperation(rop.CALL_RELEASE_GIL, - [ConstInt(0), funcbox, i1, i2], i3, + ResOperation(rop.CALL_RELEASE_GIL_I, + [ConstInt(0), funcbox, i1, i2], descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] + i3 = ops[-2] ops[-1].setfailargs([]) ops += [ - ResOperation(rop.FINISH, [i3], None, descr=BasicFinalDescr(0)) + ResOperation(rop.FINISH, [i3], descr=BasicFinalDescr(0)) ] looptoken = JitCellToken() self.cpu.compile_loop([i1, i2], ops, looptoken) @@ -3072,16 +3072,16 @@ rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_ALT_ERRNO, ]: faildescr = BasicFailDescr(1) - inputargs = [BoxInt() for i in range(7)] - i1 = BoxInt() + inputargs = [InputArgInt() for i in range(7)] ops = [ - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [ConstInt(saveerr), ConstInt(func1_adr)] - + inputargs, i1, + + inputargs, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), - ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0)) + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] + i1 = ops[0] + ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))] ops[-2].setfailargs([]) looptoken = JitCellToken() self.cpu.compile_loop(inputargs, ops, looptoken) @@ -3142,16 +3142,16 @@ rffi.RFFI_READSAVED_LASTERROR | rffi.RFFI_ALT_ERRNO, ]: faildescr = BasicFailDescr(1) - inputargs = [BoxInt() for i in range(7)] - i1 = BoxInt() + inputargs = [InputArgInt() for i in range(7)] ops = [ - ResOperation(rop.CALL_RELEASE_GIL, + ResOperation(rop.CALL_RELEASE_GIL_I, [ConstInt(saveerr), ConstInt(func1_adr)] - + inputargs, i1, + + inputargs, descr=calldescr), - ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), - ResOperation(rop.FINISH, [i1], None, descr=BasicFinalDescr(0)) + ResOperation(rop.GUARD_NOT_FORCED, [], descr=faildescr), ] + i1 = ops[-2] + ops += [ResOperation(rop.FINISH, [i1], descr=BasicFinalDescr(0))] ops[-2].setfailargs([]) looptoken = JitCellToken() self.cpu.compile_loop(inputargs, ops, looptoken) diff --git a/rpython/jit/backend/test/test_ll_random.py b/rpython/jit/backend/test/test_ll_random.py --- a/rpython/jit/backend/test/test_ll_random.py +++ b/rpython/jit/backend/test/test_ll_random.py @@ -2,9 +2,8 @@ from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr from rpython.rtyper import rclass from rpython.jit.backend.test import test_random -from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.history import ConstInt, ConstPtr -from rpython.jit.metainterp.history import BoxPtr +from rpython.jit.metainterp.resoperation import ResOperation, rop, optypes +from rpython.jit.metainterp.history import ConstInt, ConstPtr, getkind from rpython.jit.codewriter import heaptracker from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.rtyper.annlowlevel import llhelper @@ -101,10 +100,12 @@ kwds['hints'] = {'vtable': with_vtable._obj} for i in range(r.randrange(1, 5)): if r.random() < 0.1: + kind = 'r' TYPE = llmemory.GCREF else: + kind = 'i' TYPE = self.get_random_primitive_type(r) - fields.append(('f%d' % i, TYPE)) + fields.append(('%s%d' % (kind, i), TYPE)) S = type('S%d' % self.counter, *fields, **kwds) self.counter += 1 if cache: @@ -120,7 +121,7 @@ self.vtable_counter += 1 S = self.get_random_structure_type(r, with_vtable=vtable, cache=False) name = S._name - vtable.name = rclass.alloc_array_name(name) + heaptracker.set_testing_vtable_for_gcstruct(S, vtable, name) self.structure_types_and_vtables.append((S, vtable)) # return S, vtable @@ -168,7 +169,7 @@ if length == 0: raise test_random.CannotProduceOperation v_index = r.choice(self.intvars) - if not (0 <= v_index.value < length): + if not (0 <= v_index.getint() < length): v_index = ConstInt(r.random_integer() % length) return v_index @@ -242,14 +243,14 @@ if r.random() < 0.5: return GuardClassOperation.gen_guard(self, builder, r) else: - v = BoxPtr(lltype.nullptr(llmemory.GCREF.TO)) - op = ResOperation(rop.SAME_AS, [ConstPtr(v.value)], v) + NULL = lltype.nullptr(llmemory.GCREF.TO) + op = ResOperation(rop.SAME_AS_R, [ConstPtr(NULL)]) builder.loop.operations.append(op) v2, S2 = builder.get_structptr_var(r, must_have_vtable=True) vtable2 = S2._hints['vtable']._as_ptr() c_vtable2 = ConstAddr(llmemory.cast_ptr_to_adr(vtable2), builder.cpu) - op = ResOperation(self.opnum, [v, c_vtable2], None) + op = ResOperation(self.opnum, [op, c_vtable2], None) return op, False class ZeroPtrFieldOperation(test_random.AbstractOperation): @@ -263,7 +264,7 @@ choice = [] for name in names: FIELD = getattr(S, name) - if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc(): + if FIELD is lltype.Signed: # xxx should be a gc ptr, but works too choice.append(name) if not choice: raise test_random.CannotProduceOperation @@ -282,10 +283,12 @@ if names[0] == 'parent': names = names[1:] choice = [] + kind = optypes[self.opnum] for name in names: FIELD = getattr(S, name) if not isinstance(FIELD, lltype.Ptr): - choice.append(name) + if kind == 'n' or getkind(FIELD)[0] == kind: + choice.append(name) if not choice: raise test_random.CannotProduceOperation name = r.choice(choice) @@ -341,7 +344,8 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(TYPE, value)) == value: break builder.do(self.opnum, [v, w], descr) @@ -353,13 +357,14 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(TYPE, value)) == value: break builder.do(self.opnum, [v, v_index, w], descr) class NewOperation(test_random.AbstractOperation): - def size_descr(self, builder, S): - descr = builder.cpu.sizeof(S) + def size_descr(self, builder, S, *vtable): + descr = builder.cpu.sizeof(S, *vtable) descr._random_info = 'cpu.sizeof(...)' descr._random_type = S return descr @@ -367,13 +372,11 @@ def produce_into(self, builder, r): if self.opnum == rop.NEW_WITH_VTABLE: S, vtable = builder.get_random_structure_type_and_vtable(r) - args = [ConstAddr(llmemory.cast_ptr_to_adr(vtable), builder.cpu)] - descr = None + descr = self.size_descr(builder, S, vtable) else: S = builder.get_random_structure_type(r) - args = [] descr = self.size_descr(builder, S) - v_ptr = builder.do(self.opnum, args, descr) + v_ptr = builder.do(self.opnum, [], descr) builder.ptrvars.append((v_ptr, S)) class ArrayOperation(test_random.AbstractOperation): @@ -408,7 +411,8 @@ w = ConstInt(r.random_integer()) else: w = r.choice(builder.intvars) - if rffi.cast(lltype.Signed, rffi.cast(A.OF, w.value)) == w.value: + value = w.getint() + if rffi.cast(lltype.Signed, rffi.cast(A.OF, value)) == value: break builder.do(self.opnum, [v, v_index, w], descr) @@ -486,7 +490,7 @@ class AbstractSetItemOperation(AbstractStringOperation): def produce_into(self, builder, r): v_string = self.get_string(builder, r) - if not isinstance(v_string, BoxPtr): + if isinstance(v_string, ConstPtr): raise test_random.CannotProduceOperation # setitem(Const, ...) v_index = builder.get_index(len(v_string.getref(self.ptr).chars), r) v_target = ConstInt(r.random_integer() % self.max) @@ -501,13 +505,15 @@ def produce_into(self, builder, r): v_srcstring = self.get_string(builder, r) v_dststring = self.get_string(builder, r) - if v_srcstring.value == v_dststring.value: # because it's not a + src = v_srcstring.getref(self.ptr) + dst = v_dststring.getref(self.ptr) + if src == dst: # because it's not a raise test_random.CannotProduceOperation # memmove(), but memcpy() - srclen = len(v_srcstring.getref(self.ptr).chars) - dstlen = len(v_dststring.getref(self.ptr).chars) + srclen = len(src.chars) + dstlen = len(dst.chars) v_length = builder.get_index(min(srclen, dstlen), r) - v_srcstart = builder.get_index(srclen - v_length.value + 1, r) - v_dststart = builder.get_index(dstlen - v_length.value + 1, r) + v_srcstart = builder.get_index(srclen - v_length.getint() + 1, r) + v_dststart = builder.get_index(dstlen - v_length.getint() + 1, r) builder.do(self.opnum, [v_srcstring, v_dststring, v_srcstart, v_dststart, v_length]) @@ -548,16 +554,22 @@ class BaseCallOperation(test_random.AbstractOperation): def non_raising_func_code(self, builder, r): subset = builder.subset_of_intvars(r) - if len(subset) == 0: - sum = "" - funcargs = "" + funcargs = ", ".join(['arg_%d' % i for i in range(len(subset))]) + sum = "intmask(%s)" % " + ".join( + ['arg_%d' % i for i in range(len(subset))] + ['42']) + if self.opnum == rop.CALL_I: + result = 'sum' + elif self.opnum == rop.CALL_F: + result = 'float(sum)' + elif self.opnum == rop.CALL_N: + result = '' else: - funcargs = ", ".join(['arg_%d' % i for i in range(len(subset))]) - sum = "intmask(%s)" % " + ".join(['arg_%d' % i for i in range(len(subset))]) + raise AssertionError(self.opnum) code = py.code.Source(""" def f(%s): - return %s - """ % (funcargs, sum)).compile() + sum = %s + return %s + """ % (funcargs, sum, result)).compile() d = {'intmask' : intmask} exec code in d return subset, d['f'] @@ -573,14 +585,25 @@ """ % funcargs).compile() vtableptr = v._hints['vtable']._as_ptr() d = { - 'ptr': S.value, + 'ptr': S.getref_base(), 'vtable' : vtableptr, 'LLException' : LLException, } exec code in d return subset, d['f'], vtableptr + def getresulttype(self): + if self.opnum == rop.CALL_I: + return lltype.Signed + elif self.opnum == rop.CALL_F: + return lltype.Float + elif self.opnum == rop.CALL_N or self.opnum == rop.COND_CALL: + return lltype.Void + else: + raise AssertionError(self.opnum) + def getcalldescr(self, builder, TP): + assert TP.RESULT == self.getresulttype() ef = EffectInfo.MOST_GENERAL return builder.cpu.calldescrof(TP, TP.ARGS, TP.RESULT, ef) @@ -589,17 +612,14 @@ def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f = self.non_raising_func_code(builder, r) - if len(subset) == 0: - RES = lltype.Void - else: - RES = lltype.Signed + RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -609,10 +629,7 @@ class CallOperationException(BaseCallOperation): def produce_into(self, builder, r): subset, f = self.non_raising_func_code(builder, r) - if len(subset) == 0: - RES = lltype.Void - else: - RES = lltype.Signed + RES = self.getresulttype() TP = lltype.FuncType([lltype.Signed] * len(subset), RES) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) @@ -621,7 +638,7 @@ self.put(builder, args, descr) _, vtableptr = builder.get_random_structure_type_and_vtable(r) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], descr=builder.getfaildescr()) op.setfailargs(builder.subset_of_intvars(r)) op._exc_box = None @@ -642,7 +659,7 @@ descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -658,7 +675,7 @@ args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], BoxPtr(), + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) @@ -682,7 +699,7 @@ if vtableptr != exc: break other_box = ConstAddr(llmemory.cast_ptr_to_adr(vtableptr), builder.cpu) - op = ResOperation(rop.GUARD_EXCEPTION, [other_box], BoxPtr(), + op = ResOperation(rop.GUARD_EXCEPTION, [other_box], descr=builder.getfaildescr()) op._exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op.setfailargs(builder.subset_of_intvars(r)) @@ -713,7 +730,7 @@ args = [v_cond, c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) - op = ResOperation(rop.GUARD_NO_EXCEPTION, [], None, + op = ResOperation(rop.GUARD_NO_EXCEPTION, [], descr=builder.getfaildescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op) @@ -723,17 +740,18 @@ OPERATIONS = test_random.OPERATIONS[:] for i in range(4): # make more common - OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC)) - OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC)) - OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC)) + OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC_I)) + OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC_I)) + OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC_I)) + OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC_I)) OPERATIONS.append(SetFieldOperation(rop.SETFIELD_GC)) OPERATIONS.append(ZeroPtrFieldOperation(rop.ZERO_PTR_FIELD)) OPERATIONS.append(SetInteriorFieldOperation(rop.SETINTERIORFIELD_GC)) OPERATIONS.append(NewOperation(rop.NEW)) OPERATIONS.append(NewOperation(rop.NEW_WITH_VTABLE)) - OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC)) - OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC)) + OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC_I)) + OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC_I)) OPERATIONS.append(SetArrayItemOperation(rop.SETARRAYITEM_GC)) OPERATIONS.append(NewArrayOperation(rop.NEW_ARRAY_CLEAR)) OPERATIONS.append(ArrayLenOperation(rop.ARRAYLEN_GC)) @@ -750,14 +768,16 @@ for i in range(2): OPERATIONS.append(GuardClassOperation(rop.GUARD_CLASS)) - OPERATIONS.append(CallOperation(rop.CALL)) - OPERATIONS.append(RaisingCallOperation(rop.CALL)) - OPERATIONS.append(RaisingCallOperationGuardNoException(rop.CALL)) - OPERATIONS.append(RaisingCallOperationWrongGuardException(rop.CALL)) - OPERATIONS.append(CallOperationException(rop.CALL)) OPERATIONS.append(CondCallOperation(rop.COND_CALL)) + OPERATIONS.append(RaisingCallOperation(rop.CALL_N)) + OPERATIONS.append(RaisingCallOperationGuardNoException(rop.CALL_N)) + OPERATIONS.append(RaisingCallOperationWrongGuardException(rop.CALL_N)) OPERATIONS.append(GuardNonNullClassOperation(rop.GUARD_NONNULL_CLASS)) +for _opnum in [rop.CALL_I, rop.CALL_F, rop.CALL_N]: + OPERATIONS.append(CallOperation(_opnum)) + OPERATIONS.append(CallOperationException(_opnum)) + LLtypeOperationBuilder.OPERATIONS = OPERATIONS # ____________________________________________________________ diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -8,7 +8,7 @@ from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.jit.metainterp.resoperation import InputArgInt, InputArgRef from rpython.jit.metainterp.resoperation import InputArgFloat -from rpython.jit.metainterp.executor import execute_nonspec_const +from rpython.jit.metainterp.executor import _execute_arglist, wrap_constant from rpython.jit.metainterp.resoperation import opname from rpython.jit.codewriter import longlong from rpython.rtyper.lltypesystem import lltype, rstr @@ -56,11 +56,18 @@ self.fakemetainterp._got_exc = None op = ResOperation(opnum, argboxes, descr) if opnum != rop.ZERO_PTR_FIELD: - assert op.type != VOID, op - c_result = execute_nonspec_const(self.cpu, self.fakemetainterp, - opnum, argboxes, descr, - type=op.type) - op.copy_value_from(c_result) + result = _execute_arglist(self.cpu, self.fakemetainterp, + opnum, argboxes, descr) + if result is not None: + c_result = wrap_constant(result) + op.copy_value_from(c_result) + else: + import ctypes + addr = self.cpu.cast_gcref_to_int(argboxes[0].getref_base()) + offset = argboxes[1].getint() + assert (offset % ctypes.sizeof(ctypes.c_long)) == 0 + ptr = ctypes.cast(addr, ctypes.POINTER(ctypes.c_long)) + ptr[offset / ctypes.sizeof(ctypes.c_long)] = 0 self.loop.operations.append(op) return op @@ -300,6 +307,8 @@ elif v_result.type == FLOAT: builder.floatvars.append(v_result) assert self.boolres != True + elif v_result.type == VOID: + assert self.boolres != True else: raise NotImplementedError(v_result) @@ -828,6 +837,8 @@ op = self.should_fail_by if not op.getfailargs(): return False + for _fail_box in fail_args: + _fail_box.set_forwarded(None) # generate the branch: a sequence of operations that ends in a FINISH subloop = DummyLoop([]) self.subloops.append(subloop) # keep around for debugging diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -175,12 +175,12 @@ for i in range(4): mc.MOV_sr(i * WORD, cond_call_register_arguments[i].value) mc.CALL(eax) + self._reload_frame_if_necessary(mc) if IS_X86_64: mc.ADD(esp, imm(WORD)) else: mc.ADD(esp, imm(WORD * 7)) self.set_extra_stack_depth(mc, 0) - self._reload_frame_if_necessary(mc, align_stack=True) self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only) mc.RET() @@ -244,14 +244,15 @@ mc.MOV_rs(edi.value, WORD * 3) # load the itemsize self.set_extra_stack_depth(mc, 16) mc.CALL(imm(follow_jump(addr))) + self._reload_frame_if_necessary(mc) mc.ADD_ri(esp.value, 16 - WORD) + self.set_extra_stack_depth(mc, 0) + # mc.TEST_rr(eax.value, eax.value) mc.J_il(rx86.Conditions['Z'], 0xfffff) # patched later jz_location = mc.get_relative_pos() # nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr() - self._reload_frame_if_necessary(mc, align_stack=True) - self.set_extra_stack_depth(mc, 0) self._pop_all_regs_from_frame(mc, [eax, edi], self.cpu.supports_floats) mc.MOV(edi, heap(nursery_free_adr)) # load this in EDI self.pop_gcmap(mc) # push_gcmap(store=True) done by the caller @@ -1050,8 +1051,7 @@ cb = callbuilder.CallBuilder(self, fnloc, arglocs) cb.emit_no_collect() - def _reload_frame_if_necessary(self, mc, align_stack=False, - shadowstack_reg=None): + def _reload_frame_if_necessary(self, mc, shadowstack_reg=None): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: if gcrootmap.is_shadow_stack: @@ -1065,7 +1065,7 @@ # frame never uses card marking, so we enforce this is not # an array self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, - is_frame=True, align_stack=align_stack) + is_frame=True) genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") @@ -2083,7 +2083,7 @@ # ------------------- END CALL ASSEMBLER ----------------------- def _write_barrier_fastpath(self, mc, descr, arglocs, array=False, - is_frame=False, align_stack=False): + is_frame=False): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls a # helper piece of assembler. The latter saves registers as needed @@ -2139,13 +2139,9 @@ # if not is_frame: mc.PUSH(loc_base) - if is_frame and align_stack: - mc.SUB_ri(esp.value, 16 - WORD) # erase the return address mc.CALL(imm(self.wb_slowpath[helper_num])) if not is_frame: mc.stack_frame_size_delta(-WORD) - if is_frame and align_stack: - mc.ADD_ri(esp.value, 16 - WORD) # erase the return address if card_marking: # The helper ends again with a check of the flag in the object. diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -134,6 +134,8 @@ self.final_jump_op = None def _prepare(self, inputargs, operations, allgcrefs): + for box in inputargs: + assert box.get_forwarded() is None cpu = self.assembler.cpu self.fm = X86FrameManager(cpu.get_baseofs_of_frame_field()) operations = cpu.gc_ll_descr.rewrite_assembler(cpu, operations, diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -2,7 +2,7 @@ from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib.debug import debug_start, debug_stop, debug_print +from rpython.rlib.debug import debug_start, debug_stop, debug_print, have_debug_prints from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib import rstack from rpython.rlib.jit import JitDebugInfo, Counters, dont_look_inside @@ -531,6 +531,7 @@ loop.inputargs, operations, original_jitcell_token, name=loopname, + log=have_debug_prints(), memo=memo) finally: debug_stop("jit-backend") @@ -577,7 +578,8 @@ try: asminfo = do_compile_bridge(metainterp_sd, faildescr, inputargs, operations, - original_loop_token, memo) + original_loop_token, have_debug_prints(), + memo) finally: debug_stop("jit-backend") metainterp_sd.profiler.end_backend() 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 @@ -256,7 +256,6 @@ self.optearlyforce = None self.optunroll = None - self._emitting = True self._last_guard_op = None self.set_optimizations(optimizations) @@ -586,6 +585,7 @@ self.force_box(farg) elif op.can_raise(): self.exception_might_have_happened = True +<<<<<<< local if self._emitting: if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): pass @@ -593,6 +593,10 @@ self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) +======= + self._really_emitted_operation = op + self._newoperations.append(op) +>>>>>>> other def _copy_resume_data_from(self, guard_op, last_guard_op): descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -434,18 +434,6 @@ return label_args - def is_call_pure_with_exception(self, op): - if op.is_call_pure(): - effectinfo = op.getdescr().get_extra_info() - # Assert that only EF_ELIDABLE_CANNOT_RAISE or - # EF_ELIDABLE_OR_MEMORYERROR end up here, not - # for example EF_ELIDABLE_CAN_RAISE. - assert effectinfo.extraeffect in ( - effectinfo.EF_ELIDABLE_CANNOT_RAISE, - effectinfo.EF_ELIDABLE_OR_MEMORYERROR) - return effectinfo.extraeffect != effectinfo.EF_ELIDABLE_CANNOT_RAISE - return False - class UnrollInfo(LoopInfo): """ A state after optimizing the peeled loop, contains the following: From noreply at buildbot.pypy.org Thu Sep 17 11:28:57 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 17 Sep 2015 11:28:57 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: costmodel now working again and ported most part of accum as well Message-ID: <20150917092857.318391C0148@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79663:b304567d9f23 Date: 2015-09-17 11:29 +0200 http://bitbucket.org/pypy/pypy/changeset/b304567d9f23/ Log: costmodel now working again and ported most part of accum as well diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -1,13 +1,13 @@ from rpython.jit.metainterp.history import (VECTOR, FLOAT, INT, ConstInt, ConstFloat, TargetToken) from rpython.jit.metainterp.resoperation import (rop, ResOperation, - GuardResOp, VecOperation, OpHelpers) + GuardResOp, VecOperation, OpHelpers, VecOperationNew) from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.renamer import Renamer from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.jitexc import NotAProfitableLoop -from rpython.rlib.objectmodel import specialize +from rpython.rlib.objectmodel import specialize, always_inline class SchedulerState(object): @@ -133,27 +133,52 @@ assert node.emitted class TypeRestrict(object): - ANY_TYPE = -1 + ANY_TYPE = '\x00' ANY_SIZE = -1 ANY_SIGN = -1 ANY_COUNT = -1 SIGNED = 1 UNSIGNED = 0 - def __init__(self, type=-1, bytesize=-1, count=-1, sign=-1): + def __init__(self, + type=ANY_TYPE, + bytesize=ANY_SIZE, + count=ANY_SIGN, + sign=ANY_COUNT): self.type = type self.bytesize = bytesize self.sign = sign self.count = count - def allows(self, type, count): - if self.type != ANY_TYPE: - if self.type != type.type: - return False + @always_inline + def any_size(self): + return self.bytesize == TypeRestrict.ANY_SIZE - # TODO + def check(self, value): + assert value.datatype != '\x00' + if self.type != TypeRestrict.ANY_TYPE: + if self.type != value.datatype: + assert 0, "type mismatch" - return True + assert value.bytesize > 0 + if not self.any_size(): + if self.bytesize != value.bytesize: + assert 0, "size mismatch" + + assert value.count > 0 + if self.count != TypeRestrict.ANY_COUNT: + if self.count != value.count: + assert 0, "count mismatch" + + if self.sign != TypeRestrict.ANY_SIGN: + if bool(self.sign) != value.sign: + assert 0, "sign mismatch" + + def max_input_count(self, count): + """ How many """ + if self.count != TypeRestrict.ANY_COUNT: + return self.count + return count class trans(object): @@ -205,32 +230,22 @@ def turn_into_vector(state, pack): """ Turn a pack into a vector instruction """ - # - # TODO self.check_if_pack_supported(pack) - op = pack.leftmost() - args = op.getarglist() + check_if_pack_supported(state, pack) + state.costmodel.record_pack_savings(pack, pack.numops()) + left = pack.leftmost() + args = left.getarglist_copy() prepare_arguments(state, pack, args) - vop = VecOperation(op.vector, args, op, pack.numops(), op.getdescr()) + vecop = VecOperation(left.vector, args, left, + pack.numops(), left.getdescr()) + state.oplist.append(vecop) for i,node in enumerate(pack.operations): op = node.getoperation() - state.setvector_of_box(op,i,vop) - # + state.setvector_of_box(op,i,vecop) if op.is_guard(): assert isinstance(op, GuardResOp) - assert isinstance(vop, GuardResOp) - vop.setfailargs(op.getfailargs()) - vop.rd_snapshot = op.rd_snapshot - state.costmodel.record_pack_savings(pack, pack.numops()) - # - if pack.is_accumulating(): - box = oplist[position].result - assert box is not None - for node in pack.operations: - op = node.getoperation() - assert not op.returns_void() - state.renamer.start_renaming(op, box) - # - state.oplist.append(vop) + assert isinstance(vecop, GuardResOp) + vecop.setfailargs(op.getfailargs()) + vecop.rd_snapshot = op.rd_snapshot def prepare_arguments(state, pack, args): @@ -238,7 +253,9 @@ # The following cases can occur: # 1) argument is present in the box_to_vbox map. # a) vector can be reused immediatly (simple case) - # b) an operation forces the unpacking of a vector + # b) the size of the input is mismatching (crop the vector) + # c) values are scattered in differnt registers + # d) the operand is not at the right position in the vector # 2) argument is not known to reside in a vector # a) expand vars/consts before the label and add as argument # b) expand vars created in the loop body @@ -250,24 +267,49 @@ if i >= len(restrictions) or restrictions[i] is None: # ignore this argument continue + restrict = restrictions[i] if arg.returns_vector(): + restrict.check(arg) continue pos, vecop = state.getvector_of_box(arg) if not vecop: # 2) constant/variable expand this box expand(state, pack, args, arg, i) + restrict.check(args[i]) continue + # 1) + args[i] = vecop # a) + assemble_scattered_values(state, pack, args, i) # c) + crop_vector(state, restrict, pack, args, i) # b) + position_values(state, restrict, pack, args, i, pos) # d) + restrict.check(args[i]) + + at always_inline +def crop_vector(state, restrict, pack, args, i): + # convert size i64 -> i32, i32 -> i64, ... + arg = args[i] + newsize, size = restrict.bytesize, arg.bytesize + if not restrict.any_size() and newsize != size: + assert arg.type == 'i' + state._prevent_signext(newsize, size) + count = arg.count + vecop = VecOperationNew(rop.VEC_INT_SIGNEXT, [arg, ConstInt(newsize)], + 'i', newsize, arg.signed, count) + state.oplist.append(vecop) + state.costmodel.record_cast_int(size, newsize, count) args[i] = vecop - assemble_scattered_values(state, pack, args, i) - position_values(state, pack, args, i, pos) + at always_inline def assemble_scattered_values(state, pack, args, index): - vectors = pack.argument_vectors(state, pack, index) + args_at_index = [node.getoperation().getarg(index) for node in pack.operations] + args_at_index[0] = args[index] + vectors = pack.argument_vectors(state, pack, index, args_at_index) if len(vectors) > 1: # the argument is scattered along different vector boxes args[index] = gather(state, vectors, pack.numops()) state.remember_args_in_vector(pack, index, args[index]) + at always_inline def gather(state, vectors, count): # packed < packable and packed < stride: (_, arg) = vectors[0] i = 1 @@ -278,39 +320,32 @@ i += 1 return arg -def position_values(state, pack, args, index, position): + at always_inline +def position_values(state, restrict, pack, args, index, position): if position != 0: # The vector box is at a position != 0 but it # is required to be at position 0. Unpack it! arg = args[index] - args[index] = unpack_from_vector(state, arg, position, arg.count - position) + count = restrict.max_input_count(arg.count) + args[index] = unpack_from_vector(state, arg, position, count) state.remember_args_in_vector(pack, index, args[index]) - # convert size i64 -> i32, i32 -> i64, ... - # TODO if self.bytesize > 0: - # determine_trans( - # self.input_type.getsize() != vecop.getsize(): - # vecop = self.extend(vecop, self.input_type) - -def check_if_pack_supported(self, pack): - op0 = pack.operations[0].getoperation() - if self.input_type is None: - # must be a load/guard op - return - insize = self.input_type.getsize() - if op0.is_typecast(): +def check_if_pack_supported(state, pack): + left = pack.leftmost() + insize = left.bytesize + if left.is_typecast(): # prohibit the packing of signext calls that # cast to int16/int8. - _, outsize = op0.cast_to() - self.sched_data._prevent_signext(outsize, insize) - if op0.getopnum() == rop.INT_MUL: + state._prevent_signext(left.cast_to_bytesize(), + left.cast_from_bytesize()) + if left.getopnum() == rop.INT_MUL: if insize == 8 or insize == 1: # see assembler for comment why raise NotAProfitableLoop def unpack_from_vector(state, arg, index, count): """ Extract parts of the vector box into another vector box """ - print "unpack i", index, "c", count, "v", arg + #print "unpack i", index, "c", count, "v", arg assert count > 0 assert index + count <= arg.count args = [arg, ConstInt(index), ConstInt(count)] @@ -702,12 +737,12 @@ vector register. """ before_count = len(packlist) - print "splitting pack", self + #print "splitting pack", self pack = self while pack.pack_load(vec_reg_size) > Pack.FULL: pack.clear() oplist, newoplist = pack.slice_operations(vec_reg_size) - print " split of %dx, left: %d" % (len(oplist), len(newoplist)) + #print " split of %dx, left: %d" % (len(oplist), len(newoplist)) pack.operations = oplist pack.update_pack_of_nodes() if not pack.leftmost().is_typecast(): @@ -723,7 +758,7 @@ newpack.clear() newpack.operations = [] break - print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) + #print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): @@ -749,11 +784,10 @@ accum = False return rightmost is leftmost and accum - def argument_vectors(self, state, pack, index): - args = [node.getoperation().getarg(index) for node in pack.operations] + def argument_vectors(self, state, pack, index, pack_args_index): vectors = [] last = None - for arg in args: + for arg in pack_args_index: pos, vecop = state.getvector_of_box(arg) if vecop is not last and vecop is not None: vectors.append((pos, vecop)) @@ -792,23 +826,3 @@ assert isinstance(right, Node) Pair.__init__(self, left, right) self.accum = accum - -#def extend(self, vbox, newtype): -# assert vbox.gettype() == newtype.gettype() -# if vbox.gettype() == INT: -# return self.extend_int(vbox, newtype) -# else: -# raise NotImplementedError("cannot yet extend float") -# -#def extend_int(self, vbox, newtype): -# vbox_cloned = newtype.new_vector_box(vbox.getcount()) -# self.sched_data._prevent_signext(newtype.getsize(), vbox.getsize()) -# newsize = newtype.getsize() -# assert newsize > 0 -# op = ResOperation(rop.VEC_INT_SIGNEXT, -# [vbox, ConstInt(newsize)], -# vbox_cloned) -# self.costmodel.record_cast_int(vbox.getsize(), newtype.getsize(), vbox.getcount()) -# self.vecops.append(op) -# return vbox_cloned - diff --git a/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py b/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py --- a/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_costmodel.py @@ -141,7 +141,7 @@ savings = self.savings(loop1) assert savings == 2 - @py.test.mark.parametrize("bytes,s", [(1,None),(2,None),(4,0),(8,0)]) + @py.test.mark.parametrize("bytes,s", [(1,0),(2,0),(4,0),(8,0)]) def test_sum_float_to_int(self, bytes, s): loop1 = self.parse_trace(""" f10 = raw_load_f(p0, i0, descr=double) @@ -200,5 +200,16 @@ except NotAProfitableLoop: pass + def test_force_long_to_int_cast(self): + trace = self.parse_trace(""" + i10 = raw_load_i(p0, i1, descr=long) + i11 = raw_load_i(p0, i2, descr=long) + f10 = cast_int_to_float(i10) + f11 = cast_int_to_float(i11) + """) + number = self.savings(trace) + assert number == 1 + + class Test(CostModelBaseTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -23,7 +23,8 @@ from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, Scheduler, Pack, Pair, AccumPair) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt -from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, Accum) +from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, + Accum, OpHelpers, VecOperation) from rpython.rlib import listsort from rpython.rlib.objectmodel import we_are_translated from rpython.rlib.debug import debug_print, debug_start, debug_stop @@ -643,8 +644,10 @@ def record_cast_int(self, fromsize, tosize, count): # for each move there is 1 instruction - self.savings += -count - print "$$$ cast", -count, "now", self.savings + if fromsize == 8 and tosize == 4 and count == 2: + self.savings -= 1 + else: + self.savings += -count def record_vector_pack(self, src, index, count): if src.datatype == FLOAT: @@ -700,7 +703,6 @@ if self.profitable_pack(lnode, rnode, origin_pack, forward): return Pair(lnode, rnode) else: - print "dependent" if self.contains_pair(lnode, rnode): return None if origin_pack is not None: @@ -787,7 +789,7 @@ size = INT_WORD if left.type == 'f': size = FLOAT_WORD - if left.bytesize == right.bytesize and left.bytesize == size: + if not (left.bytesize == right.bytesize and left.bytesize == size): # do not support if if the type size is smaller # than the cpu word size. # WHY? @@ -811,35 +813,34 @@ for pack in self.packs: if not pack.is_accumulating(): continue - xxx accum = pack.accum - # create a new vector box for the parameters - box = pack.input_type.new_vector_box() - size = vec_reg_size // pack.input_type.getsize() + datatype = accum.getdatatype() + bytesize = accum.getbytesize() + count = vec_reg_size // bytesize + signed = datatype == 'i' + oplist = state.invariant_oplist # reset the box to zeros or ones if accum.operator == Accum.PLUS: - op = ResOperation(rop.VEC_BOX, [ConstInt(size)], box) - state.invariant_oplist.append(op) - result = box.clonebox() - op = ResOperation(rop.VEC_INT_XOR, [box, box], result) - state.invariant_oplist.append(op) - box = result + vecop = OpHelpers.create_vec(datatype, bytesize, signed) + oplist.append(vecop) + vecop = VecOperation(rop.VEC_INT_XOR, [vecop, vecop], + vecop, count) + oplist.append(vecop) elif accum.operator == Accum.MULTIPLY: # multiply is only supported by floats - op = ResOperation(rop.VEC_FLOAT_EXPAND, [ConstFloat(1.0), ConstInt(size)], box) - state.invariant_oplist.append(op) + vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize, + signed, count) + oplist.append(vecop) else: - raise NotImplementedError("can only handle %s" % accum.operator) - result = box.clonebox() - assert isinstance(result, BoxVector) - result.accum = accum + raise NotImplementedError("cannot handle %s" % accum.operator) # pack the scalar value - op = ResOperation(getpackopnum(box.gettype()), - [box, accum.var, ConstInt(0), ConstInt(1)], result) - state.invariant_oplist.append(op) + args = [vecop, accum.getseed(), ConstInt(0), ConstInt(1)] + vecop = OpHelpers.create_vec_pack(datatype, args, bytesize, + signed, count) + oplist.append(vecop) # rename the variable with the box - state.setvector_of_box(accum.getoriginalbox(), 0, result) # prevent it from expansion - state.renamer.start_renaming(accum.getoriginalbox(), result) + state.setvector_of_box(accum.getseed(), 0, vecop) # prevent it from expansion + state.renamer.start_renaming(accum.getseed(), vecop) def split_overloaded_packs(self): newpacks = [] diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -637,15 +637,16 @@ if opnum == rop.FLOAT_MUL: self.operator = Accum.MULTIPLY - def getoriginalbox(self): + def getdatatype(self): + return self.var.datatype + + def getbytesize(self): + return self.var.bytesize + + def getseed(self): + """ The variable holding the seed value """ return self.var - def getop(self): - return self.operator - - def accumulates_value(self): - return True - class CastOp(object): _mixin_ = True @@ -653,7 +654,7 @@ return True def cast_to(self): - _, _, to_type, size = self.casts + to_type, size = self.casts[2], self.casts[3] if self.casts[3] == 0: if self.getopnum() == rop.INT_SIGNEXT: from rpython.jit.metainterp.history import ConstInt From noreply at buildbot.pypy.org Thu Sep 17 12:22:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 12:22:17 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: pfff Message-ID: <20150917102217.98FE51C13BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79664:c96512000a0f Date: 2015-09-17 12:21 +0200 http://bitbucket.org/pypy/pypy/changeset/c96512000a0f/ Log: pfff 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 @@ -585,18 +585,12 @@ self.force_box(farg) elif op.can_raise(): self.exception_might_have_happened = True -<<<<<<< local - if self._emitting: - if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): - pass - else: - self._last_guard_op = None - self._really_emitted_operation = op - self._newoperations.append(op) -======= + if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): + pass + else: + self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) ->>>>>>> other def _copy_resume_data_from(self, guard_op, last_guard_op): descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) From noreply at buildbot.pypy.org Thu Sep 17 12:35:32 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 17 Sep 2015 12:35:32 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: reanimating the assembler with the new method names Message-ID: <20150917103532.251C31C13BD@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79665:63c213404528 Date: 2015-09-17 12:35 +0200 http://bitbucket.org/pypy/pypy/changeset/63c213404528/ Log: reanimating the assembler with the new method names 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 @@ -212,7 +212,6 @@ kind == 'int' or \ kind == '' - def is_always_pure(self): return self._is_pure diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -3,7 +3,7 @@ from rpython.jit.backend.llsupport.symbolic import WORD from rpython.jit.backend.llsupport.codemap import CodemapBuilder from rpython.jit.metainterp.history import (INT, REF, FLOAT, VECTOR, - JitCellToken, ConstInt, BoxInt, AbstractFailDescr, BoxVector) + JitCellToken, ConstInt, AbstractFailDescr) from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.rlib import rgc from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints_for, diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -7,8 +7,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import (Const, Box, VOID, - BoxVector, ConstInt) +from rpython.jit.metainterp.history import (Const, VOID, ConstInt) from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory @@ -1105,7 +1104,7 @@ def genop_cmp_float(self, op, arglocs, result_loc): if need_direct_p: direct_case = not isinstance(arglocs[1], RegLoc) - else: + else: direct_case = isinstance(arglocs[0], RegLoc) if direct_case: self.mc.UCOMISD(arglocs[0], arglocs[1]) @@ -1777,7 +1776,7 @@ # Note that the typeid half-word is at offset 0 on a little-endian # machine; it would be at offset 2 or 4 on a big-endian machine. assert self.cpu.supports_guard_gc_type - if IS_X86_32: + if IS_X86_32: self.mc.CMP16(mem(loc_ptr, 0), loc_expected_typeid) else: assert isinstance(loc_expected_typeid, ImmedLoc) @@ -2092,7 +2091,7 @@ self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) - def _genop_guard_call_may_force(self, op, guard_op, guard_token, + def _genop_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) self._genop_call(op, arglocs, result_loc) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -22,9 +22,8 @@ from rpython.jit.backend.x86.vector_ext import VectorRegallocMixin from rpython.jit.codewriter import longlong from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr, - ConstFloat, BoxInt, BoxFloat, BoxVector, INT, REF, - FLOAT, VECTOR, TargetToken) +from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr, + ConstFloat, INT, REF, FLOAT, VECTOR, TargetToken) from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.metainterp.resume import AccumInfo @@ -1168,7 +1167,7 @@ consider_raw_load_i = _consider_getarrayitem consider_raw_load_f = _consider_getarrayitem - def _consider_getinteriorfield_gc(self, op): + def _consider_getinteriorfield(self, op): t = unpack_interiorfielddescr(op.getdescr()) ofs, itemsize, fieldsize, sign = imm(t[0]), imm(t[1]), imm(t[2]), t[3] if sign: @@ -1205,7 +1204,7 @@ argloc = self.loc(op.getarg(0)) self.rm.possibly_free_var(op.getarg(0)) resloc = self.force_allocate_reg_or_cc(op) - self.perform(op, [argloc], resloc) + self.perform(op, [argloc], resloc) consider_int_is_zero = consider_int_is_true diff --git a/rpython/jit/backend/x86/test/test_x86vector.py b/rpython/jit/backend/x86/test/test_x86vector.py --- a/rpython/jit/backend/x86/test/test_x86vector.py +++ b/rpython/jit/backend/x86/test/test_x86vector.py @@ -5,13 +5,13 @@ (TestRegallocPushPop as BaseTestAssembler) from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.metainterp.history import ConstFloat -from rpython.jit.metainterp.test import support, test_metavec +from rpython.jit.metainterp.test import support, test_vector from rpython.jit.metainterp.warmspot import ll_meta_interp from rpython.rlib.jit import JitDriver from rpython.rtyper.lltypesystem import lltype -class TestBasic(test_metavec.VectorizeLLtypeTests, test_basic.Jit386Mixin): +class TestBasic(test_vector.VectorizeLLtypeTests, test_basic.Jit386Mixin): # for the individual tests see # ====> ../../../metainterp/test/test_basic.py enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -1,7 +1,6 @@ import py from rpython.jit.metainterp.compile import ResumeGuardDescr -from rpython.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr, - ConstFloat, BoxInt, BoxFloat, BoxVector, INT, REF, +from rpython.jit.metainterp.history import (ConstInt, INT, REF, FLOAT, VECTOR, TargetToken) from rpython.jit.backend.llsupport.descr import (ArrayDescr, CallDescr, unpack_arraydescr, unpack_fielddescr, unpack_interiorfielddescr) @@ -131,22 +130,29 @@ not_implemented("reduce sum for %s not impl." % arg) - def genop_vec_getarrayitem_raw(self, op, arglocs, resloc): + def _genop_vec_getarrayitem(self, op, arglocs, resloc): # considers item scale (raw_load does not) base_loc, ofs_loc, size_loc, ofs, integer_loc, aligned_loc = arglocs scale = get_scale(size_loc.value) src_addr = addr_add(base_loc, ofs_loc, ofs.value, scale) self._vec_load(resloc, src_addr, integer_loc.value, size_loc.value, aligned_loc.value) + + genop_vec_getarrayitem_raw_i = _genop_vec_getarrayitem + genop_vec_getarrayitem_raw_f = _genop_vec_getarrayitem + + genop_vec_getarrayitem_gc_i = _genop_vec_getarrayitem + genop_vec_getarrayitem_gc_f = _genop_vec_getarrayitem - genop_vec_getarrayitem_gc = genop_vec_getarrayitem_raw - - def genop_vec_raw_load(self, op, arglocs, resloc): + def _genop_vec_raw_load(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, ofs, integer_loc, aligned_loc = arglocs src_addr = addr_add(base_loc, ofs_loc, ofs.value, 0) self._vec_load(resloc, src_addr, integer_loc.value, size_loc.value, aligned_loc.value) + genop_vec_raw_load_i = _genop_vec_raw_load + genop_vec_raw_load_f = _genop_vec_raw_load + def _vec_load(self, resloc, src_addr, integer, itemsize, aligned): if integer: if aligned: @@ -159,7 +165,7 @@ elif itemsize == 8: self.mc.MOVUPD(resloc, src_addr) - def genop_discard_vec_setarrayitem_raw(self, op, arglocs): + def _genop_discard_vec_setarrayitem(self, op, arglocs): # considers item scale (raw_store does not) base_loc, ofs_loc, value_loc, size_loc, baseofs, integer_loc, aligned_loc = arglocs scale = get_scale(size_loc.value) @@ -167,7 +173,8 @@ self._vec_store(dest_loc, value_loc, integer_loc.value, size_loc.value, aligned_loc.value) - genop_discard_vec_setarrayitem_gc = genop_discard_vec_setarrayitem_raw + genop_discard_vec_setarrayitem_raw = _genop_discard_vec_setarrayitem + genop_discard_vec_setarrayitem_gc = _genop_discard_vec_setarrayitem def genop_discard_vec_raw_store(self, op, arglocs): base_loc, ofs_loc, value_loc, size_loc, baseofs, integer_loc, aligned_loc = arglocs @@ -385,7 +392,7 @@ msg = "vec int signext (%d->%d)" % (size, tosize) not_implemented(msg) - def genop_vec_float_expand(self, op, arglocs, resloc): + def genop_vec_expand_f(self, op, arglocs, resloc): srcloc, sizeloc = arglocs size = sizeloc.value if isinstance(srcloc, ConstFloatLoc): @@ -401,7 +408,7 @@ else: raise AssertionError("float of size %d not supported" % (size,)) - def genop_vec_int_expand(self, op, arglocs, resloc): + def genop_vec_expand_i(self, op, arglocs, resloc): srcloc, sizeloc = arglocs if not isinstance(srcloc, RegLoc): self.mov(srcloc, X86_64_SCRATCH_REG) @@ -425,7 +432,7 @@ else: raise AssertionError("cannot handle size %d (int expand)" % (size,)) - def genop_vec_int_pack(self, op, arglocs, resloc): + def genop_vec_pack_i(self, op, arglocs, resloc): resultloc, sourceloc, residxloc, srcidxloc, countloc, sizeloc = arglocs assert isinstance(resultloc, RegLoc) assert isinstance(sourceloc, RegLoc) @@ -477,9 +484,9 @@ ri += 1 k -= 1 - genop_vec_int_unpack = genop_vec_int_pack + genop_vec_unpack_i = genop_vec_pack_i - def genop_vec_float_pack(self, op, arglocs, resultloc): + def genop_vec_pack_f(self, op, arglocs, resultloc): resloc, srcloc, residxloc, srcidxloc, countloc, sizeloc = arglocs assert isinstance(resloc, RegLoc) assert isinstance(srcloc, RegLoc) @@ -533,7 +540,7 @@ self.mc.UNPCKHPD(resloc, srcloc) # if they are equal nothing is to be done - genop_vec_float_unpack = genop_vec_float_pack + genop_vec_unpack_f = genop_vec_pack_f def genop_vec_cast_float_to_singlefloat(self, op, arglocs, resloc): self.mc.CVTPD2PS(resloc, arglocs[0]) @@ -550,7 +557,7 @@ class VectorRegallocMixin(object): _mixin_ = True - def consider_vec_getarrayitem_raw(self, op): + def _consider_vec_getarrayitem(self, op): descr = op.getdescr() assert isinstance(descr, ArrayDescr) assert not descr.is_array_of_pointers() and \ @@ -565,10 +572,14 @@ self.perform(op, [base_loc, ofs_loc, imm(itemsize), imm(ofs), imm(integer), imm(aligned)], result_loc) - consider_vec_getarrayitem_gc = consider_vec_getarrayitem_raw - consider_vec_raw_load = consider_vec_getarrayitem_raw + consider_vec_getarrayitem_raw_i = _consider_vec_getarrayitem + consider_vec_getarrayitem_raw_f = _consider_vec_getarrayitem + consider_vec_getarrayitem_gc_i = _consider_vec_getarrayitem + consider_vec_getarrayitem_gc_f = _consider_vec_getarrayitem + consider_vec_raw_load_i = _consider_vec_getarrayitem + consider_vec_raw_load_f = _consider_vec_getarrayitem - def consider_vec_setarrayitem_raw(self, op): + def _consider_vec_setarrayitem(self, op): descr = op.getdescr() assert isinstance(descr, ArrayDescr) assert not descr.is_array_of_pointers() and \ @@ -584,8 +595,9 @@ self.perform_discard(op, [base_loc, ofs_loc, value_loc, imm(itemsize), imm(ofs), imm(integer), imm(aligned)]) - consider_vec_setarrayitem_gc = consider_vec_setarrayitem_raw - consider_vec_raw_store = consider_vec_setarrayitem_raw + consider_vec_setarrayitem_raw = _consider_vec_setarrayitem + consider_vec_setarrayitem_gc = _consider_vec_setarrayitem + consider_vec_raw_store = _consider_vec_setarrayitem def consider_vec_arith(self, op): lhs = op.getarg(0) @@ -647,8 +659,8 @@ consider_vec_int_xor = consider_vec_logic del consider_vec_logic - def consider_vec_int_pack(self, op): - # new_res = vec_int_pack(res, src, index, count) + def consider_vec_pack_i(self, op): + # new_res = vec_pack_i(res, src, index, count) arg = op.getarg(1) index = op.getarg(2) count = op.getarg(3) @@ -664,9 +676,9 @@ arglocs = [resloc, srcloc, imm(residx), imm(srcidx), imm(count.value), imm(size)] self.perform(op, arglocs, resloc) - consider_vec_float_pack = consider_vec_int_pack + consider_vec_pack_f = consider_vec_pack_i - def consider_vec_int_unpack(self, op): + def consider_vec_unpack_i(self, op): index = op.getarg(1) count = op.getarg(2) assert isinstance(index, ConstInt) @@ -688,14 +700,14 @@ arglocs = [resloc, srcloc, imm(residx), imm(index.value), imm(count.value), imm(size)] self.perform(op, arglocs, resloc) - consider_vec_float_unpack = consider_vec_int_unpack + consider_vec_unpack_f = consider_vec_unpack_i - def consider_vec_float_expand(self, op): + def consider_vec_expand_f(self, op): result = op.result assert isinstance(result, BoxVector) arg = op.getarg(0) args = op.getarglist() - if isinstance(arg, Const): + if arg.is_constant(): resloc = self.xrm.force_allocate_reg(result) srcloc = self.xrm.expand_float(result.getsize(), arg) else: @@ -705,10 +717,10 @@ size = op.result.getsize() self.perform(op, [srcloc, imm(size)], resloc) - def consider_vec_int_expand(self, op): + def consider_vec_expand_i(self, op): arg = op.getarg(0) args = op.getarglist() - if isinstance(arg, Const): + if arg.is_constant(): srcloc = self.rm.convert_to_imm(arg) else: srcloc = self.make_sure_var_in_reg(arg, args) @@ -739,9 +751,12 @@ else: self.perform(op, [resloc,imm(size)], None) - def consider_vec_box(self, op): + def _consider_vec(self, op): # pseudo instruction, needed to create a new variable self.xrm.force_allocate_reg(op.result) + + consider_vec_i = _consider_vec + consider_vec_f = _consider_vec def consider_guard_early_exit(self, op): pass From noreply at buildbot.pypy.org Thu Sep 17 12:46:48 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Thu, 17 Sep 2015 12:46:48 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: test reproducing the problem Message-ID: <20150917104648.4EAA91C13BD@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79666:7942aa26d427 Date: 2015-09-17 10:58 +0200 http://bitbucket.org/pypy/pypy/changeset/7942aa26d427/ Log: test reproducing the problem diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py --- a/rpython/translator/stm/test/test_ztranslated.py +++ b/rpython/translator/stm/test/test_ztranslated.py @@ -738,3 +738,25 @@ t, cbuilder = self.compile(main) data = cbuilder.cmdexec('') assert 'ok!\n' in data + + def test_allocate_noconflict3(self): + MAPDICT_CACHE = lltype.GcArray(llmemory.GCREF) + + class CacheEntry(object): pass + INVALID_CACHE_ENTRY = CacheEntry() + + class P(): pass + pbc = P() + pbc.cache = rstm.allocate_noconflict(MAPDICT_CACHE, 5) + for i in range(5): + pbc.cache[i] = cast_instance_to_gcref(INVALID_CACHE_ENTRY) + + def main(argv): + assert cast_gcref_to_instance(CacheEntry, pbc.cache[1]) is INVALID_CACHE_ENTRY + # + print "ok!" + return 0 + + t, cbuilder = self.compile(main) + data = cbuilder.cmdexec('') + assert 'ok!\n' in data From noreply at buildbot.pypy.org Thu Sep 17 14:00:30 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 14:00:30 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix the case of sharing descrs from preamble Message-ID: <20150917120030.BC8B21C1215@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79667:5b0ebf3c8f4f Date: 2015-09-17 14:00 +0200 http://bitbucket.org/pypy/pypy/changeset/5b0ebf3c8f4f/ Log: fix the case of sharing descrs from preamble 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 @@ -572,7 +572,7 @@ return else: guard_op = self.replace_op_with(op, op.getopnum()) - if self._last_guard_op: + if self._last_guard_op and guard_op.getdescr() is None: op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1088,7 +1088,7 @@ return s self.meta_interp(f, [30]) - self.check_trace_count(4) + self.check_trace_count(3) class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Thu Sep 17 15:04:44 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 15:04:44 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: forbid sharing guard_value for now Message-ID: <20150917130444.9FDBC1C210C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79668:7777998d3adf Date: 2015-09-17 15:04 +0200 http://bitbucket.org/pypy/pypy/changeset/7777998d3adf/ Log: forbid sharing guard_value for now 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 @@ -572,7 +572,8 @@ return else: guard_op = self.replace_op_with(op, op.getopnum()) - if self._last_guard_op and guard_op.getdescr() is None: + if (self._last_guard_op and guard_op.getdescr() is None and + guard_op.getopnum() != rop.GUARD_VALUE): op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: From noreply at buildbot.pypy.org Thu Sep 17 15:19:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 17 Sep 2015 15:19:02 +0200 (CEST) Subject: [pypy-commit] cffi default: Remove a dictionary order dependency (idnar on irc) Message-ID: <20150917131902.2CECA1C0148@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2271:1cfe8c7a59e8 Date: 2015-09-17 15:19 +0200 http://bitbucket.org/cffi/cffi/changeset/1cfe8c7a59e8/ Log: Remove a dictionary order dependency (idnar on irc) diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -879,7 +879,9 @@ # because they don't have any known C name. Check that they are # not partial (we can't complete or verify them!) and emit them # anonymously. - for tp in list(self._struct_unions): + lst = self._struct_unions.items() + lst.sort(key=lambda (tp, order): order) + for tp, order in lst: if tp not in self._seen_struct_unions: if tp.partial: raise NotImplementedError("internal inconsistency: %r is " From noreply at buildbot.pypy.org Thu Sep 17 16:07:12 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Thu, 17 Sep 2015 16:07:12 +0200 (CEST) Subject: [pypy-commit] stmgc default: add XXX about possible performance issue Message-ID: <20150917140713.0CA3A1C1215@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: Changeset: r1962:41227d7659ac Date: 2015-09-17 16:07 +0200 http://bitbucket.org/pypy/stmgc/changeset/41227d7659ac/ Log: add XXX about possible performance issue diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -424,6 +424,8 @@ We choose the approach to reset all our changes to this obj here, so that we can throw away the backup copy completely: */ + /* XXX: this browses through the whole list of modified + fragments; this may become a problem... */ reset_modified_from_backup_copies(my_segnum, obj); continue; } From noreply at buildbot.pypy.org Thu Sep 17 17:31:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 17 Sep 2015 17:31:24 +0200 (CEST) Subject: [pypy-commit] pypy default: misuse of 'static' Message-ID: <20150917153124.5C0031C1215@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79669:83e44b8fbe30 Date: 2015-09-17 17:31 +0200 http://bitbucket.org/pypy/pypy/changeset/83e44b8fbe30/ Log: misuse of 'static' diff --git a/rpython/rlib/rvmprof/src/vmprof_main.h b/rpython/rlib/rvmprof/src/vmprof_main.h --- a/rpython/rlib/rvmprof/src/vmprof_main.h +++ b/rpython/rlib/rvmprof/src/vmprof_main.h @@ -328,7 +328,7 @@ static int install_sigprof_timer(void) { - static struct itimerval timer; + struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = profile_interval_usec; timer.it_value = timer.it_interval; @@ -338,7 +338,7 @@ } static int remove_sigprof_timer(void) { - static struct itimerval timer; + struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 0; From noreply at buildbot.pypy.org Thu Sep 17 17:59:05 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Thu, 17 Sep 2015 17:59:05 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: The problem in the previous commit seems to be that INVALID_CACHE_ENTRY is Message-ID: <20150917155905.ABE911C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79670:9ca388f9503e Date: 2015-09-17 17:58 +0200 http://bitbucket.org/pypy/pypy/changeset/9ca388f9503e/ Log: The problem in the previous commit seems to be that INVALID_CACHE_ENTRY is prebuilt. It is enough to make it not prebuilt to pass the test. Painfully adapt code in mapdict.py to make sure its not prebuilt... diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -837,36 +837,53 @@ return True return False -_invalid_cache_entry_map = objectmodel.instantiate(AbstractAttribute) -_invalid_cache_entry_map.terminator = None -INVALID_CACHE_ENTRY = CacheEntry() -INVALID_CACHE_ENTRY.map_wref = weakref.ref(_invalid_cache_entry_map) + def _cleanup_(self): + raise Exception("cannot translate a prebuilt CacheEntry") # for unknown reasons + +# _invalid_cache_entry_map = objectmodel.instantiate(AbstractAttribute) +# _invalid_cache_entry_map.terminator = None +# INVALID_CACHE_ENTRY = CacheEntry() +# INVALID_CACHE_ENTRY.map_wref = weakref.ref(_invalid_cache_entry_map) # different from any real map ^^^ from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper import annlowlevel MAPDICT_CACHE = lltype.GcArray(llmemory.GCREF) -PMAPDICT_CACHE = lltype.Ptr(MAPDICT_CACHE) NULL_MAPDICTCACHE = lltype.nullptr(MAPDICT_CACHE) +def init_mapdict_cache(pycode): + # pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries + pycode._mapdict_caches = NULL_MAPDICTCACHE -def init_mapdict_cache(pycode): +def lazy_init_mapdict_cache(pycode): + assert we_are_translated() num_entries = len(pycode.co_names_w) - # pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries if pycode.space.config.translation.stm: from rpython.rlib.rstm import allocate_noconflict pycode._mapdict_caches = allocate_noconflict(MAPDICT_CACHE, num_entries) else: pycode._mapdict_caches = lltype.malloc(MAPDICT_CACHE, num_entries) # + # create invalid entry (should be prebuilt, but then translation fails) + _invalid_cache_entry_map = objectmodel.instantiate(AbstractAttribute) + _invalid_cache_entry_map.terminator = None + pycode._mapdict_cache_invalid = CacheEntry() + pycode._mapdict_cache_invalid.map_wref = weakref.ref(_invalid_cache_entry_map) + # different from any real map ^^^ + # for i in range(num_entries): - pycode._mapdict_caches[i] = annlowlevel.cast_instance_to_gcref(INVALID_CACHE_ENTRY) + pycode._mapdict_caches[i] = annlowlevel.cast_instance_to_gcref(pycode._mapdict_cache_invalid) @jit.dont_look_inside def _fill_cache(pycode, nameindex, map, version_tag, storageindex, w_method=None): + if not we_are_translated(): + return + if pycode._mapdict_caches is NULL_MAPDICTCACHE: + lazy_init_mapdict_cache(pycode) + # entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) - if entry is INVALID_CACHE_ENTRY: + if entry is pycode._mapdict_cache_invalid: entry = CacheEntry() pycode._mapdict_caches[nameindex] = annlowlevel.cast_instance_to_gcref(entry) entry.map_wref = weakref.ref(map) @@ -879,6 +896,11 @@ def LOAD_ATTR_caching(pycode, w_obj, nameindex): # this whole mess is to make the interpreter quite a bit faster; it's not # used if we_are_jitted(). + if not we_are_translated(): + return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, w_obj._get_mapdict_map()) + if pycode._mapdict_caches is NULL_MAPDICTCACHE: + lazy_init_mapdict_cache(pycode) + # entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) map = w_obj._get_mapdict_map() if entry.is_valid_for_map(map) and entry.w_method is None: @@ -930,12 +952,17 @@ _fill_cache(pycode, nameindex, map, version_tag, attr.storageindex) return w_obj._mapdict_read_storage(attr.storageindex) if space.config.objspace.std.withmethodcachecounter: - INVALID_CACHE_ENTRY.failure_counter += 1 + pycode._mapdict_cache_invalid.failure_counter += 1 return space.getattr(w_obj, w_name) LOAD_ATTR_slowpath._dont_inline_ = True def LOOKUP_METHOD_mapdict(f, nameindex, w_obj): pycode = f.getcode() + if not we_are_translated(): + return False + if pycode._mapdict_caches is NULL_MAPDICTCACHE: + lazy_init_mapdict_cache(pycode) + # entry = annlowlevel.cast_gcref_to_instance(CacheEntry, pycode._mapdict_caches[nameindex]) if entry.is_valid_for_obj(w_obj): w_method = entry.w_method diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -719,21 +719,25 @@ def check(space, w_func, name): w_code = space.getattr(w_func, space.wrap('func_code')) nameindex = map(space.str_w, w_code.co_names_w).index(name) + if not w_code._mapdict_caches:# is NULL_MAPDICTCACHE: + lazy_init_mapdict_cache(w_code) + # entry = annlowlevel.cast_gcref_to_instance(CacheEntry, w_code._mapdict_caches[nameindex]) entry.failure_counter = 0 entry.success_counter = 0 - INVALID_CACHE_ENTRY.failure_counter = 0 + # INVALID_CACHE_ENTRY.failure_counter = 0 + w_code._mapdict_cache_invalid.failure_counter = 0 # w_res = space.call_function(w_func) assert space.eq_w(w_res, space.wrap(42)) # entry = annlowlevel.cast_gcref_to_instance(CacheEntry, w_code._mapdict_caches[nameindex]) - if entry is INVALID_CACHE_ENTRY: + if entry is w_code._mapdict_cache_invalid: failures = successes = 0 else: failures = entry.failure_counter successes = entry.success_counter - globalfailures = INVALID_CACHE_ENTRY.failure_counter + globalfailures = w_code._mapdict_cache_invalid.failure_counter return space.wrap((failures, successes, globalfailures)) check.unwrap_spec = [gateway.ObjSpace, gateway.W_Root, str] cls.w_check = cls.space.wrap(gateway.interp2app(check)) diff --git a/rpython/translator/stm/test/test_ztranslated.py b/rpython/translator/stm/test/test_ztranslated.py --- a/rpython/translator/stm/test/test_ztranslated.py +++ b/rpython/translator/stm/test/test_ztranslated.py @@ -741,18 +741,27 @@ def test_allocate_noconflict3(self): MAPDICT_CACHE = lltype.GcArray(llmemory.GCREF) + NULL_MAPDICTCACHE = lltype.nullptr(MAPDICT_CACHE) class CacheEntry(object): pass - INVALID_CACHE_ENTRY = CacheEntry() + # INVALID_CACHE_ENTRY = CacheEntry() class P(): pass pbc = P() - pbc.cache = rstm.allocate_noconflict(MAPDICT_CACHE, 5) - for i in range(5): - pbc.cache[i] = cast_instance_to_gcref(INVALID_CACHE_ENTRY) + pbc.cache = NULL_MAPDICTCACHE + + def init(): + pbc.cache = rstm.allocate_noconflict(MAPDICT_CACHE, 5) + for i in range(5): + pbc.cache[i] = cast_instance_to_gcref(pbc.invalid) + + pbc.init = init def main(argv): - assert cast_gcref_to_instance(CacheEntry, pbc.cache[1]) is INVALID_CACHE_ENTRY + if pbc.cache is NULL_MAPDICTCACHE: + pbc.invalid = CacheEntry() + pbc.init() + assert cast_gcref_to_instance(CacheEntry, pbc.cache[1]) is pbc.invalid # print "ok!" return 0 From noreply at buildbot.pypy.org Thu Sep 17 17:59:08 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Thu, 17 Sep 2015 17:59:08 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: reenable mapdict cache and method cache (needs testing) Message-ID: <20150917155908.1DEAF1C0933@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79671:72a2bd026996 Date: 2015-09-17 17:59 +0200 http://bitbucket.org/pypy/pypy/changeset/72a2bd026996/ Log: reenable mapdict cache and method cache (needs testing) diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -324,8 +324,9 @@ if config.translation.stm: # having both mapdict and methodcache together is a bad idea: # it creates many conflicts - if config.objspace.std.withmapdict: - config.objspace.std.withmethodcache = False + # if config.objspace.std.withmapdict: + # config.objspace.std.withmethodcache = True #False + pass def enable_allworkingmodules(config): diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -15,7 +15,7 @@ CO_GENERATOR, CO_KILL_DOCSTRING, CO_YIELD_INSIDE_TRY) from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT from rpython.rlib.rarithmetic import intmask, r_longlong -from rpython.rlib.objectmodel import compute_hash +from rpython.rlib.objectmodel import compute_hash, we_are_translated from rpython.rlib import jit from rpython.rlib.debug import debug_start, debug_stop, debug_print @@ -57,7 +57,7 @@ _immutable_fields_ = ["co_consts_w[*]", "co_names_w[*]", "co_varnames[*]", "co_freevars[*]", "co_cellvars[*]", "_args_as_cellvars[*]"] - + def __init__(self, space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, name, firstlineno, lnotab, freevars, cellvars, @@ -123,11 +123,11 @@ self._compute_flatcall() - if (self.space.config.objspace.std.withmapdict and - not self.space.config.translation.stm): + if self.space.config.objspace.std.withmapdict: from pypy.objspace.std.mapdict import init_mapdict_cache init_mapdict_cache(self) + def _init_ready(self): "This is a hook for the vmprof module, which overrides this method." @@ -369,6 +369,7 @@ code = space.allocate_instance(PyCode, w_subtype) PyCode.__init__(code, space, argcount, nlocals, stacksize, flags, codestring, consts_w[:], names, varnames, filename, name, firstlineno, lnotab, freevars, cellvars, magic=magic) + return space.wrap(code) def descr__reduce__(self, space): diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -958,7 +958,6 @@ "obj.attributename" w_obj = self.popvalue() if (self.space.config.objspace.std.withmapdict and - not self.space.config.translation.stm and not jit.we_are_jitted()): from pypy.objspace.std.mapdict import LOAD_ATTR_caching w_value = LOAD_ATTR_caching(self.getcode(), w_obj, nameindex) diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py --- a/pypy/objspace/std/callmethod.py +++ b/pypy/objspace/std/callmethod.py @@ -34,7 +34,6 @@ w_obj = f.popvalue() if (space.config.objspace.std.withmapdict and - not space.config.translation.stm and not jit.we_are_jitted()): # mapdict has an extra-fast version of this function if LOOKUP_METHOD_mapdict(f, nameindex, w_obj): @@ -62,7 +61,6 @@ f.pushvalue(w_descr) f.pushvalue(w_obj) if (space.config.objspace.std.withmapdict and - not space.config.translation.stm and not jit.we_are_jitted()): # let mapdict cache stuff LOOKUP_METHOD_mapdict_fill_cache_method( From noreply at buildbot.pypy.org Thu Sep 17 18:46:47 2015 From: noreply at buildbot.pypy.org (vext01) Date: Thu, 17 Sep 2015 18:46:47 +0200 (CEST) Subject: [pypy-commit] pypy detect_egd2: Fix an SSL test when LibreSSL is used. Message-ID: <20150917164647.8FDBB1C0148@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: detect_egd2 Changeset: r79672:e065a97685b3 Date: 2015-09-17 17:46 +0100 http://bitbucket.org/pypy/pypy/changeset/e065a97685b3/ Log: Fix an SSL test when LibreSSL is used. diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -36,7 +36,8 @@ assert isinstance(_ssl.OPENSSL_VERSION_INFO, tuple) assert len(_ssl.OPENSSL_VERSION_INFO) == 5 assert isinstance(_ssl.OPENSSL_VERSION, str) - assert 'openssl' in _ssl.OPENSSL_VERSION.lower() + lower_version = _ssl.OPENSSL_VERSION.lower() + assert 'openssl' in lower_version or "libressl" in lower_version assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int) From noreply at buildbot.pypy.org Thu Sep 17 18:50:16 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 17 Sep 2015 18:50:16 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: reanimated vecopt integration tests that use the assembler backend. not quite sure yet how to come along supports_gc_type Message-ID: <20150917165016.7227E1C0148@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79673:32891e533aab Date: 2015-09-17 18:50 +0200 http://bitbucket.org/pypy/pypy/changeset/32891e533aab/ Log: reanimated vecopt integration tests that use the assembler backend. not quite sure yet how to come along supports_gc_type diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -52,6 +52,10 @@ else: translator = None self.gc_ll_descr = get_ll_description(gcdescr, translator, rtyper) + # support_guard_gc_type indicates if a gc type of an object can be read. + # In some states (boehm or x86 untranslated) the type is not known just yet, + # because there are cases where it is not guarded. The precise place where it's not + # is while inlining short preamble. self.supports_guard_gc_type = self.gc_ll_descr.supports_guard_gc_type if translator and translator.config.translation.gcremovetypeptr: self.vtable_offset = None diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -648,7 +648,7 @@ startpos = self.mc.get_relative_pos() self.store_info_on_descr(startpos, tok) else: - regalloc.position = tok.position + # TODO regalloc.position = tok.position tok.pos_recovery_stub = self.generate_quick_failure(tok, regalloc) if WORD == 8 and len(self.pending_memoryerror_trampoline_from) > 0: self.error_trampoline_64 = self.generate_propagate_error_64() @@ -1654,27 +1654,27 @@ self.mc.PUNPCKLDQ_xx(resloc.value, loc1.value) def genop_guard_guard_true(self, guard_op, guard_token, locs, resloc): - loc = locs[0] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self._guard_vector_true(guard_op, loc) - # XXX - self.implement_guard(guard_token, 'NZ') - return - self.mc.TEST(loc, loc) + #loc = locs[0] + #if isinstance(loc, RegLoc): + # if loc.is_xmm: + # self._guard_vector_true(guard_op, loc) + # # XXX + # self.implement_guard(guard_token, 'NZ') + # return + #self.mc.TEST(loc, loc) self.implement_guard(guard_token) genop_guard_guard_nonnull = genop_guard_guard_true def genop_guard_guard_false(self, guard_op, guard_token, locs, resloc): self.guard_success_cc = rx86.invert_condition(self.guard_success_cc) - loc = locs[0] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self._guard_vector_false(guard_op, loc) - # XXX - self.implement_guard(guard_token, 'NZ') - return - self.mc.TEST(loc, loc) + # TODO loc = locs[0] + #if isinstance(loc, RegLoc): + # if loc.is_xmm: + # self._guard_vector_false(guard_op, loc) + # # XXX + # self.implement_guard(guard_token, 'NZ') + # return + #self.mc.TEST(loc, loc) self.implement_guard(guard_token) genop_guard_guard_isnull = genop_guard_guard_false @@ -1884,7 +1884,7 @@ self.mc.JMP(imm(self.propagate_exception_path)) return startpos - def generate_quick_failure(self, guardtok): + def generate_quick_failure(self, guardtok, regalloc): """ Gather information about failure """ self.mc.force_frame_size(DEFAULT_FRAME_BYTES) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -323,8 +323,7 @@ if arg is None: faillocs.append(None) continue - accum = arg.getaccum() - if accum: + if arg.is_vector() and arg.getaccum(): # for an accumulator store the position of the original # box and in llsupport/assembler save restore information # on the descriptor diff --git a/rpython/jit/backend/x86/test/test_x86vector.py b/rpython/jit/backend/x86/test/test_x86vector.py --- a/rpython/jit/backend/x86/test/test_x86vector.py +++ b/rpython/jit/backend/x86/test/test_x86vector.py @@ -11,7 +11,7 @@ from rpython.rtyper.lltypesystem import lltype -class TestBasic(test_vector.VectorizeLLtypeTests, test_basic.Jit386Mixin): +class TestBasic(test_basic.Jit386Mixin, test_vector.VectorizeTests): # for the individual tests see # ====> ../../../metainterp/test/test_basic.py enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' 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 @@ -32,9 +32,9 @@ def build_opt_chain(metainterp_sd, enable_opts): optimizations = [] unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict - if (metainterp_sd.cpu is not None and - not metainterp_sd.cpu.supports_guard_gc_type): - unroll = False + #if (metainterp_sd.cpu is not None and + # not metainterp_sd.cpu.supports_guard_gc_type): + # unroll = False for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -132,6 +132,9 @@ self.guard_bool_bool_node = None self._stack = False + def is_imaginary(self): + return False + def getoperation(self): return self.op def getindex(self): @@ -186,8 +189,8 @@ isinstance(descr, compile.CompileLoopVersionDescr) return False - def is_guard_early_exit(self): - return self.op.getopnum() == rop.GUARD_EARLY_EXIT + # TODO def is_guard_early_exit(self): + # return self.op.getopnum() == rop.GUARD_EARLY_EXIT def loads_from_complex_object(self): return rop._ALWAYS_PURE_LAST <= self.op.getopnum() < rop._MALLOC_FIRST @@ -286,11 +289,14 @@ return True def iterate_paths(self, to, backwards=False, path_max_len=-1, blacklist=False): - """ yield all nodes from self leading to 'to'. backwards determines - the iteration direction and blacklist marks nodes that have already been visited. - blacklist comes in handy if a property must hold for every path. not *every* possible - instance must be iterated, but trees that have already been visited can be ignored - after the have been visited + """ Yield all nodes from self leading to 'to'. + + backwards: Determines the iteration direction. + blacklist: Marks nodes that have already been visited. + It comes in handy if a property must hold for every path. + Not *every* possible instance must be iterated, but trees + that have already been visited can be ignored after the + first visit. """ if self is to: return @@ -304,6 +310,8 @@ else: iterdir = node.provides() if index >= len(iterdir): + if to is None and index == 0: + yield Path(path.path[:]) if blacklist: blacklist_visit[node] = None continue @@ -322,7 +330,8 @@ continue pathlen += 1 - if next_node is to or (path_max_len > 0 and pathlen >= path_max_len): + if next_node is to or \ + (path_max_len > 0 and pathlen >= path_max_len): yield Path(path.path[:]) # note that the destiantion node ``to'' is never blacklisted #if blacklist: @@ -334,14 +343,14 @@ i = 0 while i < len(self.adjacent_list): dep = self.adjacent_list[i] - if dep.to == node: + if dep.to is node: del self.adjacent_list[i] break i += 1 i = 0 while i < len(node.adjacent_list_back): dep = node.adjacent_list_back[i] - if dep.to == self: + if dep.to is self: del node.adjacent_list_back[i] break i += 1 @@ -358,15 +367,30 @@ pack = "p: %d" % self.pack.numops() return "Node(%s,%s i: %d)" % (self.op, pack, self.opidx) - def __ne__(self, other): - return not self.__eq__(other) + def getdotlabel(self): + """ NOT_RPTYHON """ + op_str = str(self.op) + if self.op.is_guard(): + args_str = [str(arg) for arg in self.op.getfailargs()] + op_str += " " + ','.join(args_str) + return "[%d] %s" % (self.opidx, op_str) - def __eq__(self, other): - if other is None: - return False - assert isinstance(other, Node) - return self.opidx == other.opidx +class ImaginaryNode(Node): + _index = 987654321 # big enough? :) + def __init__(self, label): + index = -1 + if not we_are_translated(): + self.dotlabel = label + index = ImaginaryNode._index + ImaginaryNode._index += 1 + Node.__init__(self, None, index) + def is_imaginary(self): + return True + + def getdotlabel(self): + """ NOT_RPTYHON """ + return self.dotlabel class Dependency(object): def __init__(self, at, to, arg, failarg=False): @@ -385,6 +409,12 @@ return True return False + def target_node(self): + return self.to + + def origin_node(self): + return self.at + def to_index(self): return self.to.getindex() def at_index(self): @@ -509,7 +539,8 @@ def __init__(self, loop): self.loop = loop self.label = Node(loop.label, 0) - self.nodes = [ Node(op,i+1) for i,op in enumerate(loop.operations) ] + self.nodes = [ Node(op,i+1) for i,op in enumerate(loop.operations) if not op.is_debug() ] + self.inodes = [] # imaginary nodes self.jump = Node(loop.jump, len(self.nodes)+1) self.invariant_vars = {} self.update_invariant_vars() @@ -523,6 +554,11 @@ def getnode(self, i): return self.nodes[i] + def imaginary_node(self, label): + node = ImaginaryNode(label) + self.inodes.append(node) + return node + def update_invariant_vars(self): label_op = self.label.getoperation() jump_op = self.jump.getoperation() @@ -559,18 +595,20 @@ node.setpriority(2) # the label operation defines all operations at the # beginning of the loop - if op.getopnum() == rop.LABEL and i != jump_pos: - node.setpriority(100) - label_pos = i - for arg in op.getarglist(): - tracker.define(arg, node) - continue # prevent adding edge to the label itself - elif node.is_guard_early_exit(): - label_node = self.nodes[label_pos] - label_node.edge_to(node,None,label='L->EE') - for arg in label_node.getoperation().getarglist(): - tracker.define(arg, node) - continue + + # TODO if op.getopnum() == rop.LABEL and i != jump_pos: + # node.setpriority(100) + # label_pos = i + # for arg in op.getarglist(): + # tracker.define(arg, node) + # continue # prevent adding edge to the label itself + #elif node.is_guard_early_exit(): + # label_node = self.nodes[label_pos] + # label_node.edge_to(node,None,label='L->EE') + # for arg in label_node.getoperation().getarglist(): + # tracker.define(arg, node) + # continue + intformod.inspect_operation(op,node) # definition of a new variable if op.type != 'v': @@ -774,20 +812,22 @@ graph += "\n" return graph + " ])" + def view(self): + """ NOT_RPYTHON """ + from rpython.translator.tool.graphpage import GraphPage + page = GraphPage() + page.source = self.as_dot() + page.links = [] + page.display() + def as_dot(self): """ NOT_RPTYHON """ if not we_are_translated(): dot = "digraph dep_graph {\n" - for node in self.nodes: - op = node.getoperation() - if op.getopnum() == rop.DEBUG_MERGE_POINT: - continue - op_str = str(op) - if op.is_guard(): - op_str += " " + ','.join([str(arg) for arg in op.getfailargs()]) - dot += " n%d [label=\"[%d]: %s\"];\n" % (node.getindex(),node.getindex(),op_str) + for node in self.nodes + self.inodes: + dot += " n%d [label=\"%s\"];\n" % (node.getindex(),node.getdotlabel()) dot += "\n" - for node in self.nodes: + for node in self.nodes + self.inodes: for dep in node.provides(): label = '' if getattr(dep, 'label', None): diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -18,6 +18,7 @@ self.worklist = [] self.invariant_oplist = [] self.invariant_vector_vars = [] + self.seen = {} def post_schedule(self): loop = self.graph.loop @@ -32,17 +33,30 @@ loop.prefix_label = loop.label.copy_and_change(opnum, args) def profitable(self): - return self.costmodel.profitable() + return True def prepare(self): - pass + for node in self.graph.nodes: + if node.depends_count() == 0: + self.worklist.insert(0, node) - def delay(self): + def emit(self, node, scheduler): + # implement me in subclass. e.g. as in VecScheduleState + return False + + def delay(self, node): return False def has_more(self): return len(self.worklist) > 0 + def ensure_args_unpacked(self, op): + pass + + def post_emit(self, op): + pass + + class Scheduler(object): """ Create an instance of this class to (re)schedule a vector trace. """ def __init__(self): @@ -75,11 +89,6 @@ """ An operation has been emitted, adds new operations to the worklist whenever their dependency count drops to zero. Keeps worklist sorted (see priority) """ - op = node.getoperation() - state.renamer.rename(op) - if unpack: - state.ensure_args_unpacked(op) - node.vector=Trueposition = len(state.oplist) worklist = state.worklist for dep in node.provides()[:]: # COPY to = dep.to @@ -104,20 +113,28 @@ worklist.insert(0, to) node.clear_dependencies() node.emitted = True + if not node.is_imaginary(): + op = node.getoperation() + state.renamer.rename(op) + if unpack: + state.ensure_args_unpacked(op) + state.post_emit(node.getoperation()) def walk_and_emit(self, state): """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) + import pdb; pdb.set_trace() while state.has_more(): node = self.next(state) if node: if not state.emit(node, self): if not node.emitted: - op = node.getoperation() self.mark_emitted(node, state) - state.seen[op] = None - state.oplist.append(op) + if not node.is_imaginary(): + op = node.getoperation() + state.seen[op] = None + state.oplist.append(op) continue # it happens that packs can emit many nodes that have been @@ -246,6 +263,10 @@ assert isinstance(vecop, GuardResOp) vecop.setfailargs(op.getfailargs()) vecop.rd_snapshot = op.rd_snapshot + if pack.is_accumulating(): + for i,node in enumerate(pack.operations): + op = node.getoperation() + state.accumulation[op] = pack def prepare_arguments(state, pack, args): @@ -456,7 +477,7 @@ self.packset = packset for arg in graph.loop.inputargs: self.inputargs[arg] = None - self.seen = {} + self.accumulation = {} def expand(self, args, vecop): index = 0 @@ -496,39 +517,33 @@ return vecop return None + def post_emit(self, op): + if op.is_guard(): + # add accumulation info to the descriptor + # TODO for version in self.loop.versions: + # # this needs to be done for renamed (accum arguments) + # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] + #self.appendedvar_pos_arg_count = len(sched_data.invariant_vector_vars) + failargs = op.getfailargs() + descr = op.getdescr() + for i,arg in enumerate(failargs): + if arg is None: + continue + accum = state.accumulation.get(arg, None) + if accum: + assert isinstance(accum, AccumPack) + accum.attach_accum_info(descr.rd_accum_list, i) + def post_schedule(self): loop = self.graph.loop self.ensure_args_unpacked(loop.jump) SchedulerState.post_schedule(self) - # add accumulation info to the descriptor - # TODO for version in self.loop.versions: - # # this needs to be done for renamed (accum arguments) - # version.renamed_inputargs = [ renamer.rename_map.get(arg,arg) for arg in version.inputargs ] - #self.appended_arg_count = len(sched_data.invariant_vector_vars) - ##for guard_node in graph.guards: - ## op = guard_node.getoperation() - ## failargs = op.getfailargs() - ## for i,arg in enumerate(failargs): - ## if arg is None: - ## continue - ## accum = arg.getaccum() - ## if accum: - ## pass - ## #accum.save_to_descr(op.getdescr(),i) - #self.has_two_labels = len(sched_data.invariant_oplist) > 0 - #self.loop.operations = self.prepend_invariant_operations(sched_data) - - def profitable(self): return self.costmodel.profitable() def prepare(self): SchedulerState.prepare(self) - for node in self.graph.nodes: - if node.depends_count() == 0: - self.worklist.insert(0, node) - self.packset.accumulate_prepare(self) for arg in self.graph.loop.label.getarglist(): self.seen[arg] = None @@ -640,10 +655,14 @@ * independent """ FULL = 0 + _attrs_ = ('operations', 'accumulator', 'operator', 'position') + + operator = '\x00' + position = -1 + accumulator = None def __init__(self, ops): self.operations = ops - self.accum = None self.update_pack_of_nodes() def numops(self): @@ -776,13 +795,12 @@ rightmost = self.operations[-1] leftmost = other.operations[0] # if it is not accumulating it is valid - accum = True if self.is_accumulating(): if not other.is_accumulating(): - accum = False - elif self.accum.pos != other.accum.pos: - accum = False - return rightmost is leftmost and accum + return False + elif self.position != other.position: + return False + return rightmost is leftmost def argument_vectors(self, state, pack, index, pack_args_index): vectors = [] @@ -800,12 +818,10 @@ return "Pack(%dx %s)" % (self.numops(), self.operations) def is_accumulating(self): - return self.accum is not None + return False def clone(self, oplist): - cloned = Pack(oplist) - cloned.accum = self.accum - return cloned + return Pack(oplist) class Pair(Pack): """ A special Pack object with only two statements. """ @@ -819,10 +835,37 @@ return self.left is other.left and \ self.right is other.right -class AccumPair(Pair): - """ A pair that keeps track of an accumulation value """ - def __init__(self, left, right, accum): - assert isinstance(left, Node) - assert isinstance(right, Node) - Pair.__init__(self, left, right) - self.accum = accum +class AccumPack(Pack): + SUPPORTED = { rop.FLOAT_ADD: '+', + rop.INT_ADD: '+', + rop.FLOAT_MUL: '*', + } + + def __init__(self, nodes, operator, accum, position): + Pack.__init__(self, [left, right]) + self.accumulator = accum + self.operator = operator + self.position = position + + def getdatatype(self): + return self.accumulator.datatype + + def getbytesize(self): + return self.accumulator.bytesize + + def getseed(self): + """ The accumulatoriable holding the seed value """ + return self.accumulator + + def attach_accum_info(self, descr, position, scalar): + descr.rd_accum_list = AccumInfo(descr.rd_accum_list, + position, self.operator, + self.scalar, None) + + def is_accumulating(self): + return True + + def clone(self): + return AccumPack(operations, self.operator, + self.accumulator, self.position) + diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -58,6 +58,32 @@ op.setdescr(ResumeAtLoopHeaderDescr()) return loop + def parse_trace(self, source, inc_label_jump=True, pargs=2, iargs=10, + fargs=6, additional_args=None, replace_args=None): + args = [] + for prefix, rang in [('p',range(pargs)), + ('i',range(iargs)), + ('f',range(fargs))]: + for i in rang: + args.append(prefix + str(i)) + + assert additional_args is None or isinstance(additional_args,list) + for arg in additional_args or []: + args.append(arg) + for k,v in (replace_args or {}).items(): + for i,_ in enumerate(args): + if k == args[i]: + args[i] = v + break + indent = " " + joinedargs = ','.join(args) + fmt = (indent, joinedargs, source, indent, joinedargs) + src = "%s[%s]\n%s\n%sjump(%s)" % fmt + loop = self.parse_loop(src) + loop.graph = FakeDependencyGraph(loop) + return loop + + def assert_edges(self, graph, edge_list, exceptions): """ Check if all dependencies are met. for complex cases adding None instead of a list of integers skips the test. diff --git a/rpython/jit/metainterp/optimizeopt/test/test_guard.py b/rpython/jit/metainterp/optimizeopt/test/test_guard.py --- a/rpython/jit/metainterp/optimizeopt/test/test_guard.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_guard.py @@ -2,17 +2,17 @@ from rpython.jit.metainterp import compile from rpython.jit.metainterp.history import (TargetToken, JitCellToken, - TreeLoop, Box, Const) + TreeLoop, Const) from rpython.jit.metainterp.optimizeopt.util import equaloplists -from rpython.jit.metainterp.optimizeopt.vectorize import (VecScheduleData, - Pack, NotAProfitableLoop, VectorizingOptimizer) +from rpython.jit.metainterp.optimizeopt.vector import (Pack, + NotAProfitableLoop, VectorizingOptimizer) from rpython.jit.metainterp.optimizeopt.dependency import (Node, DependencyGraph, IndexVar) from rpython.jit.metainterp.optimizeopt.guard import (GuardStrengthenOpt, Guard) from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_schedule import SchedulerBaseTest -from rpython.jit.metainterp.optimizeopt.test.test_vectorize import (FakeMetaInterpStaticData, +from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, FakeJitDriverStaticData) from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.tool.oparser_model import get_model @@ -57,7 +57,7 @@ return self.opnum def box(value): - return Box._new(value) + return InputArgInt(value) def const(value): return Const._new(value) @@ -80,12 +80,13 @@ class GuardBaseTest(SchedulerBaseTest): def optguards(self, loop, user_code=False): - loop.snapshot() + #loop.snapshot() for op in loop.operations: if op.is_guard(): op.setdescr(compile.CompileLoopVersionDescr()) dep = DependencyGraph(loop) opt = GuardStrengthenOpt(dep.index_vars, False) + xxx opt.propagate_all_forward(loop, user_code) return opt @@ -159,7 +160,7 @@ assert j == len(operations), self.debug_print_operations(loop) def test_basic(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_lt(i1, 42) guard_true(i10) [] i11 = int_add(i1, 1) @@ -177,7 +178,7 @@ """) def test_basic_sub(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_gt(i1, 42) guard_true(i10) [] i11 = int_sub(i1, 1) @@ -195,7 +196,7 @@ """) def test_basic_mul(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_mul(i1, 4) i20 = int_lt(i10, 42) guard_true(i20) [] @@ -310,7 +311,7 @@ assert not g2.implies(g1) def test_collapse(self): - loop1 = self.parse(""" + loop1 = self.parse_trace(""" i10 = int_gt(i1, 42) guard_true(i10) [] i11 = int_add(i1, 1) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py --- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py @@ -9,8 +9,7 @@ from rpython.jit.metainterp.optimizeopt.dependency import Node, DependencyGraph from rpython.jit.metainterp.optimizeopt.schedule import Scheduler from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin -from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest, - FakeDependencyGraph) +from rpython.jit.metainterp.optimizeopt.test.test_dependency import (DependencyBaseTest) from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, FakeJitDriverStaticData) from rpython.jit.metainterp.resoperation import rop, ResOperation @@ -39,31 +38,6 @@ 'char': self.chararraydescr, } - def parse_trace(self, source, inc_label_jump=True, pargs=2, iargs=10, - fargs=6, additional_args=None, replace_args=None): - args = [] - for prefix, rang in [('p',range(pargs)), - ('i',range(iargs)), - ('f',range(fargs))]: - for i in rang: - args.append(prefix + str(i)) - - assert additional_args is None or isinstance(additional_args,list) - for arg in additional_args or []: - args.append(arg) - for k,v in (replace_args or {}).items(): - for i,_ in enumerate(args): - if k == args[i]: - args[i] = v - break - indent = " " - joinedargs = ','.join(args) - fmt = (indent, joinedargs, source, indent, joinedargs) - src = "%s[%s]\n%s\n%sjump(%s)" % fmt - loop = self.parse_loop(src) - loop.graph = FakeDependencyGraph(loop) - return loop - def pack(self, loop, l, r, input_type=None, output_type=None): return Pack(loop.graph.nodes[l:r]) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -14,6 +14,7 @@ from rpython.jit.metainterp.optimizeopt.vector import (VectorizingOptimizer, MemoryRef, isomorphic, Pair, NotAVectorizeableLoop, NotAProfitableLoop, GuardStrengthenOpt, CostModel, VectorLoop) +from rpython.jit.metainterp.optimizeopt.schedule import (Scheduler, SchedulerState) from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp import compile from rpython.jit.metainterp.resoperation import rop, ResOperation @@ -42,17 +43,24 @@ jitdriver_sd = FakeJitDriverStaticData() def assert_vectorize(self, loop, expected_loop, call_pure_results=None): - self._do_optimize_loop(loop, call_pure_results, export_state=True) + self._do_optimize_loop(loop) self.assert_equal(loop, expected_loop) def vectoroptimizer(self, loop): metainterp_sd = FakeMetaInterpStaticData(self.cpu) jitdriver_sd = FakeJitDriverStaticData() opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, 0) - label_index = loop.find_first_index(rop.LABEL) - opt.orig_label_args = loop.operations[label_index].getarglist()[:] + opt.orig_label_args = loop.label.getarglist()[:] return opt + def earlyexit(self, loop): + opt = self.vectoroptimizer(loop) + graph = opt.analyse_index_calculations(loop) + graph.view() + state = SchedulerState(graph) + opt.schedule(state) + return graph.loop + def vectoroptimizer_unrolled(self, loop, unroll_factor = -1): loop.snapshot() opt = self.vectoroptimizer(loop) @@ -185,6 +193,19 @@ class BaseTestVectorize(VecTestHelper): + def test_move_guard_first(self): + trace = self.parse_trace(""" + i10 = int_add(i0, i1) + # + i11 = int_add(i0, i1) + guard_true(i11) [] + """) + add = trace.operations[1] + guard = trace.operations[2] + trace = self.earlyexit(trace) + assert trace.operations[0] is add + assert trace.operations[1] is guard + def test_vectorize_skip(self): ops = """ [p0,i0] @@ -757,7 +778,7 @@ @pytest.mark.parametrize("descr,stride,packs,suffix", [('char',1,1,'_i'),('float',8,4,'_f'),('int',8,4,'_i'),('float32',4,2,'_i')]) - def test_packset_combine_2_loads_in_trace(self, descr, stride,packs): + def test_packset_combine_2_loads_in_trace(self, descr, stride, packs, suffix): ops = """ [p0,i0] i3 = raw_load{suffix}(p0, i0, descr={type}arraydescr) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -21,10 +21,10 @@ MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo from rpython.jit.metainterp.optimizeopt.schedule import (VecScheduleState, - Scheduler, Pack, Pair, AccumPair) + SchedulerState, Scheduler, Pack, Pair, AccumPack) from rpython.jit.metainterp.optimizeopt.guard import GuardStrengthenOpt from rpython.jit.metainterp.resoperation import (rop, ResOperation, GuardResOp, - Accum, OpHelpers, VecOperation) + OpHelpers, VecOperation) from rpython.rlib import listsort from rpython.rlib.objectmodel import we_are_translated from rpython.rlib.debug import debug_print, debug_start, debug_stop @@ -60,7 +60,7 @@ # the original loop (output of optimize_unroll) info = LoopVersionInfo(loop_info) version = info.snapshot(loop_ops, info.label_op) - loop = VectorLoop(loop_info.label_op, loop_ops[:-1], loop_ops[-1]) + loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) try: debug_start("vec-opt-loop") metainterp_sd.logger_noopt.log_loop([], loop.operation_list(), -2, None, None, "pre vectorize") @@ -160,21 +160,23 @@ self.has_two_labels = False def propagate_all_forward(self, info, loop): - label = loop.label - jump = loop.jump - self.orig_label_args = label.getarglist_copy() - if jump.getopnum() not in (rop.LABEL, rop.JUMP) or \ - label.getopnum() != rop.LABEL: - raise NotAVectorizeableLoop() - if jump.numargs() != label.numargs(): - raise NotAVectorizeableLoop() - + #label = loop.label + #jump = loop.jump + #if jump.getopnum() not in (rop.LABEL, rop.JUMP) or \ + # label.getopnum() != rop.LABEL: + # import pdb; pdb. set_trace() + # raise NotAVectorizeableLoop() + #if jump.numargs() != label.numargs(): + # import pdb; pdb. set_trace() + # raise NotAVectorizeableLoop() + self.orig_label_args = loop.label.getarglist_copy() self.linear_find_smallest_type(loop) byte_count = self.smallest_type_bytes vsize = self.cpu.vector_register_size - if vsize == 0 or byte_count == 0 or label.getopnum() != rop.LABEL: + if vsize == 0 or byte_count == 0 or loop.label.getopnum() != rop.LABEL: # stop, there is no chance to vectorize this trace # we cannot optimize normal traces (if there is no label) + import pdb; pdb. set_trace() raise NotAVectorizeableLoop() # find index guards and move to the earliest position @@ -186,7 +188,7 @@ # unroll self.unroll_count = self.get_unroll_count(vsize) self.unroll_loop_iterations(loop, self.unroll_count) - self.loop.operations = self.get_newoperations(); + loop.operations = self.get_newoperations() self.clear_newoperations(); # vectorize @@ -207,29 +209,26 @@ def unroll_loop_iterations(self, loop, unroll_count): """ Unroll the loop X times. unroll_count + 1 = unroll_factor """ - op_count = len(loop.operations) - - label_op = loop.operations[0].clone() - assert label_op.getopnum() == rop.LABEL - jump_op = loop.operations[op_count-1] - assert jump_op.getopnum() in (rop.LABEL, rop.JUMP) + numops = len(loop.operations) + label_op = loop.label + jump_op = loop.jump # use the target token of the label - target_token = label_op.getdescr() - if not we_are_translated(): - target_token.assumed_classes = {} - if jump_op.getopnum() == rop.LABEL: - jump_op = ResOperation(rop.JUMP, jump_op.getarglist(), target_token) - else: - jump_op = jump_op.clone() - jump_op.setdescr(target_token) - assert jump_op.is_final() + #target_token = label_op.getdescr() + #if not we_are_translated(): + # target_token.assumed_classes = {} + #if jump_op.getopnum() == rop.LABEL: + # jump_op = ResOperation(rop.JUMP, jump_op.getarglist(), target_token) + #else: + # jump_op = jump_op.clone() + # jump_op.setdescr(target_token) + #assert jump_op.is_final() self.emit_unrolled_operation(label_op) renamer = Renamer() operations = [] - for i in range(1,op_count-1): - op = loop.operations[i].clone() + for i in range(1,numops-1): + op = loop.operations[i].copy() if op.is_guard(): assert isinstance(op, GuardResOp) failargs = renamer.rename_failargs(op, clone=True) @@ -258,13 +257,11 @@ for i, op in enumerate(operations): if op.getopnum() in prohibit_opnums: continue # do not unroll this operation twice - copied_op = op.clone() + copied_op = op.copy() if not copied_op.returns_void(): # every result assigns a new box, thus creates an entry # to the rename map. - new_assigned_box = copied_op.result.clonebox() - renamer.start_renaming(copied_op.result, new_assigned_box) - copied_op.result = new_assigned_box + renamer.start_renaming(op, copied_op) # args = copied_op.getarglist() for a, arg in enumerate(args): @@ -518,14 +515,14 @@ step vectorization would not be possible! """ graph = DependencyGraph(loop) - ee_guard_node = graph.getnode(0) - if ee_guard_node.getopnum() != rop.GUARD_EARLY_EXIT: - raise NotAVectorizeableLoop() - label_node = graph.getnode(0) + zero_deps = {} + for node in graph.nodes: + if node.depends_count() == 0: + zero_deps[node] = 0 + earlyexit = graph.imaginary_node("early exit") guards = graph.guards + one_valid = False for guard_node in guards: - if guard_node is ee_guard_node: - continue modify_later = [] last_prev_node = None valid = True @@ -537,34 +534,35 @@ # 2) non pure operation points to this guard. # but if this guard only depends on pure operations, it can be checked # at an earlier position, the non pure op can execute later! - modify_later.append((prev_node, guard_node)) + modify_later.append(prev_node) else: - for path in prev_node.iterate_paths(ee_guard_node, backwards=True, blacklist=True): - if path.is_always_pure(exclude_first=True, exclude_last=True): - path.set_schedule_priority(10) - if path.last() is ee_guard_node: - modify_later.append((path.last_but_one(), None)) - else: - # transformation is invalid. - # exit and do not enter else branch! + for path in prev_node.iterate_paths(None, backwards=True, blacklist=True): + if not path.is_always_pure(exclude_first=True): + path.set_schedule_priority(90) valid = False + if path.last() in zero_deps: + del zero_deps[path.last()] if not valid: break if valid: # transformation is valid, modify the graph and execute # this guard earlier - for a,b in modify_later: - if b is not None: - a.remove_edge_to(b) - else: - last_but_one = a - if last_but_one is ee_guard_node: - continue - ee_guard_node.remove_edge_to(last_but_one) - #label_node.edge_to(last_but_one, label='pullup') - # only the last guard needs a connection - guard_node.edge_to(ee_guard_node, label='pullup-last-guard') - self.relax_guard_to(guard_node, ee_guard_node) + one_valid = True + for node in modify_later: + node.remove_edge_to(guard_node) + # every edge that starts in the guard, the early exit + # inherts the edge and guard then provides to early exit + for dep in guard_node.provides()[:]: + earlyexit.edge_to(dep.target_node()) + guard_node.remove_edge_to(dep.target_node()) + guard_node.edge_to(earlyexit) + + for node in zero_deps.keys(): + earlyexit.edge_to(node) + # TODO self.relax_guard_to(guard_node, ee_guard_node) + if one_valid: + return graph + return None def relax_guard_to(self, guard_node, other_node): """ Relaxes a guard operation to an earlier guard. """ @@ -686,9 +684,10 @@ """ if isomorphic(lnode.getoperation(), rnode.getoperation()): if lnode.independent(rnode): - if forward and isinstance(origin_pack, AccumPair): + if forward and origin_pack.is_accumulating(): # in this case the splitted accumulator must # be combined. This case is not supported + import pdb; pdb. set_trace() raise NotAVectorizeableLoop() # if self.contains_pair(lnode, rnode): @@ -739,20 +738,15 @@ return False def combine(self, i, j): - """ Combine two packs. it is assumed that the attribute self.packs + """ Combine two packs. It is assumed that the attribute self.packs is not iterated when calling this method. """ - pack_i = self.packs[i] - pack_j = self.packs[j] - operations = pack_i.operations - for op in pack_j.operations[1:]: + pkg_a = self.packs[i] + pkg_b = self.packs[j] + operations = pkg_a.operations + for op in pkg_b.operations[1:]: operations.append(op) - pack = Pack(operations) - self.packs[i] = pack - # preserve the accum variable (if present) - pack.accum = pack_i.accum - pack_i.accum = pack_j.accum = None - + self.packs[i] = pkg_a.clone(operations) del self.packs[j] return len(self.packs) @@ -762,27 +756,27 @@ left = lnode.getoperation() opnum = left.getopnum() - if opnum in (rop.FLOAT_ADD, rop.INT_ADD, rop.FLOAT_MUL): + if opnum in AccumPack.SUPPORTED: right = rnode.getoperation() assert left.numargs() == 2 and not left.returns_void() - accum_var, accum_pos = self.getaccumulator_variable(left, right, origin_pack) - if not accum_var: + scalar, index = self.getaccumulator_variable(left, right, origin_pack) + if not scalar: return None # the dependency exists only because of the left? for dep in lnode.provides(): if dep.to is rnode: - if not dep.because_of(accum_var): + if not dep.because_of(scalar): # not quite ... this is not handlable return None # get the original variable - accum_var = left.getarg(accum_pos) + scalar = left.getarg(index) # in either of the two cases the arguments are mixed, # which is not handled currently - var_pos = (accum_pos + 1) % 2 - if left.getarg(var_pos) is not origin_pack.leftmost(): + other_index = (index + 1) % 2 + if left.getarg(other_index) is not origin_pack.leftmost(): return None - if right.getarg(var_pos) is not origin_pack.rightmost(): + if right.getarg(other_index) is not origin_pack.rightmost(): return None # this can be handled by accumulation @@ -797,8 +791,8 @@ # of leading/preceding signext/floatcast instructions needs to be # considered. => tree pattern matching problem. return None - accum = Accum(opnum, accum_var, accum_pos) - return AccumPair(lnode, rnode, accum) + operator = AccumPack.SUPPORTED[opnum] + return AccumPack(lnode, rnode, operator, scalar, index) return None diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -256,6 +256,9 @@ # common methods # -------------- + def copy(self): + return self.copy_and_change(self.opnum) + def copy_and_change(self, opnum, args=None, descr=None): "shallow copy: the returned operation is meant to be used in place of self" # XXX specialize @@ -419,6 +422,9 @@ def is_raw_array_access(self): return self.is_raw_load() or self.is_raw_store() + def is_debug(self): + return rop._DEBUG_FIRST <= self.getopnum() <= rop._DEBUG_LAST + def is_primitive_array_access(self): """ Indicates that this operations loads/stores a primitive type (int,float) """ @@ -626,27 +632,6 @@ from rpython.jit.metainterp import history return history.ConstPtr(self.getref_base()) -class Accum(object): - PLUS = '+' - MULTIPLY = '*' - - def __init__(self, opnum, var, pos): - self.var = var - self.pos = pos - self.operator = Accum.PLUS - if opnum == rop.FLOAT_MUL: - self.operator = Accum.MULTIPLY - - def getdatatype(self): - return self.var.datatype - - def getbytesize(self): - return self.var.bytesize - - def getseed(self): - """ The variable holding the seed value """ - return self.var - class CastOp(object): _mixin_ = True @@ -726,9 +711,6 @@ return False return True - def getaccum(self): - return self.accum - class AbstractInputArg(AbstractResOpOrInputArg): def set_forwarded(self, forwarded_to): self._forwarded = forwarded_to @@ -1114,6 +1096,13 @@ # must be forced, however we need to execute it anyway '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations ----- + '_DEBUG_FIRST', + 'DEBUG_MERGE_POINT/*/n', # debugging only + 'ENTER_PORTAL_FRAME/2/n', # debugging only + 'LEAVE_PORTAL_FRAME/1/n', # debugging only + 'JIT_DEBUG/*/n', # debugging only + '_DEBUG_LAST', + 'INCREMENT_DEBUG_COUNTER/1/n', '_RAW_STORE_FIRST', 'SETARRAYITEM_GC/3d/n', @@ -1135,10 +1124,6 @@ 'UNICODESETITEM/3/n', 'COND_CALL_GC_WB/1d/n', # [objptr] (for the write barrier) 'COND_CALL_GC_WB_ARRAY/2d/n', # [objptr, arrayindex] (write barr. for array) - 'DEBUG_MERGE_POINT/*/n', # debugging only - 'ENTER_PORTAL_FRAME/2/n', # debugging only - 'LEAVE_PORTAL_FRAME/1/n', # debugging only - 'JIT_DEBUG/*/n', # debugging only 'VIRTUAL_REF_FINISH/2/n', # removed before it's passed to the backend 'COPYSTRCONTENT/5/n', # src, dst, srcstart, dststart, length 'COPYUNICODECONTENT/5/n', diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -48,7 +48,8 @@ self.pc = pc class AccumInfo(object): - __slots__ = ('prev', 'accum_operation', 'scalar_position', 'scalar_box', 'vector_loc') + _attrs_ = ('prev', 'accum_operation', 'scalar_position', 'scalar_box', 'vector_loc') + def __init__(self, prev, position, operation, box, loc): self.prev = prev self.accum_operation = operation diff --git a/rpython/jit/metainterp/test/test_vector.py b/rpython/jit/metainterp/test/test_vector.py --- a/rpython/jit/metainterp/test/test_vector.py +++ b/rpython/jit/metainterp/test/test_vector.py @@ -342,8 +342,5 @@ res = self.meta_interp(f, [size], vec_all=True) assert res == f(size) -class VectorizeLLtypeTests(VectorizeTests): +class TestLLtype(LLJitMixin, VectorizeTests): pass - -class TestLLtype(VectorizeLLtypeTests, LLJitMixin): - pass diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -71,7 +71,7 @@ backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, function_threshold=4, enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, - max_unroll_recursion=7, vec=0, vec_all=0, vec_cost=0, + max_unroll_recursion=7, vec=1, vec_all=0, vec_cost=0, vec_length=60, vec_ratio=2, vec_guard_ratio=3, **kwds): from rpython.config.config import ConfigError translator = interp.typer.annotator.translator From noreply at buildbot.pypy.org Thu Sep 17 18:54:41 2015 From: noreply at buildbot.pypy.org (vext01) Date: Thu, 17 Sep 2015 18:54:41 +0200 (CEST) Subject: [pypy-commit] pypy detect_egd2: This test also hangs on OpenBSD. Message-ID: <20150917165441.D169D1C0148@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: detect_egd2 Changeset: r79674:bf9134e756d5 Date: 2015-09-17 17:54 +0100 http://bitbucket.org/pypy/pypy/changeset/bf9134e756d5/ Log: This test also hangs on OpenBSD. diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -70,8 +70,9 @@ def test_sslwrap(self): import _ssl, _socket, sys, gc - if sys.platform == 'darwin' or 'freebsd' in sys.platform: - skip("hangs indefinitely on OSX & FreeBSD (also on CPython)") + if sys.platform == 'darwin' or 'freebsd' in sys.platform or \ + 'openbsd' in sys.platform: + skip("hangs indefinitely on OSX & BSD (also on CPython)") s = _socket.socket() if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) From noreply at buildbot.pypy.org Thu Sep 17 19:14:24 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 19:14:24 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: an attempt at sharing guards Message-ID: <20150917171424.C4AF31C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79675:95a1828c06f1 Date: 2015-09-17 19:14 +0200 http://bitbucket.org/pypy/pypy/changeset/95a1828c06f1/ Log: an attempt at sharing guards diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -68,11 +68,13 @@ the label """ def __init__(self, start_label, operations, call_pure_results=None, - enable_opts=None): + enable_opts=None, origin_jitcode=None, origin_pc=0): self.start_label = start_label self.operations = operations self.call_pure_results = call_pure_results self.enable_opts = enable_opts + self.origin_jitcode = origin_jitcode + self.origin_pc = origin_pc def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll): from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer @@ -80,19 +82,23 @@ #assert not unroll opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.propagate_all_forward(self.start_label.getarglist(), - self.operations, self.call_pure_results) + self.operations, self.call_pure_results, + origin_jitcode=self.origin_jitcode, origin_pc=self.origin_pc) class BridgeCompileData(CompileData): """ This represents ops() with a jump at the end that goes to some loop, we need to deal with virtual state and inlining of short preamble """ def __init__(self, start_label, operations, call_pure_results=None, - enable_opts=None, inline_short_preamble=False): + enable_opts=None, inline_short_preamble=False, + origin_jitcode=None, origin_pc=0): self.start_label = start_label self.operations = operations self.call_pure_results = call_pure_results self.enable_opts = enable_opts self.inline_short_preamble = inline_short_preamble + self.origin_jitcode = origin_jitcode + self.origin_pc = origin_pc def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll): from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer @@ -101,7 +107,8 @@ return opt.optimize_bridge(self.start_label, self.operations, self.call_pure_results, self.inline_short_preamble, - self.box_names_memo) + self.box_names_memo, + self.origin_jitcode, self.origin_pc) class UnrolledLoopData(CompileData): """ This represents label() ops jump with extra info that's from the @@ -675,10 +682,13 @@ class ResumeGuardDescr(ResumeDescr): _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals', - 'rd_frame_info_list', 'rd_pendingfields', 'status') + 'rd_frame_info_list', 'rd_pendingfields', 'status', + 'rd_origin_jitcode', 'rd_origin_pc') rd_numb = lltype.nullptr(NUMBERING) rd_count = 0 + rd_origin_pc = 0 + rd_origin_jitcode = None rd_consts = None rd_virtuals = None rd_frame_info_list = None @@ -990,6 +1000,9 @@ return resumedescr class ResumeFromInterpDescr(ResumeDescr): + rd_origin_jitcode = None + rd_origin_pc = 0 + def __init__(self, original_greenkey): self.original_greenkey = original_greenkey @@ -1042,11 +1055,15 @@ data = BridgeCompileData(label, operations[:], call_pure_results=call_pure_results, enable_opts=enable_opts, - inline_short_preamble=inline_short_preamble) + inline_short_preamble=inline_short_preamble, + origin_jitcode=resumekey.rd_origin_jitcode, + origin_pc=resumekey.rd_origin_pc) else: data = SimpleCompileData(label, operations[:], call_pure_results=call_pure_results, - enable_opts=enable_opts) + enable_opts=enable_opts, + origin_jitcode=resumekey.rd_origin_jitcode, + origin_pc=resumekey.rd_origin_pc) try: info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) 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 @@ -107,6 +107,8 @@ self.last_guard_pos = -1 def mark_last_guard(self, optimizer): + if optimizer.getlastop() is None: + return self.last_guard_pos = len(optimizer._newoperations) - 1 assert self.get_last_guard(optimizer).is_guard() 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 @@ -497,7 +497,10 @@ return CONST_0 def propagate_all_forward(self, inputargs, ops, call_pure_results=None, - rename_inputargs=True, flush=True): + rename_inputargs=True, flush=True, + origin_jitcode=None, origin_pc=0): + self.origin_jitcode = origin_jitcode + self.origin_pc = origin_pc if rename_inputargs: newargs = [] for inparg in inputargs: @@ -563,6 +566,14 @@ op.setarg(i, arg) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if op.is_guard(): + assert isinstance(op, GuardResOp) + if self.origin_jitcode is not None: + if (self.origin_jitcode is op.rd_frame_info_list.jitcode and + self.origin_pc is op.rd_frame_info_list.pc): + self.origin_jitcode = None + self.origin_pc = 0 + else: + return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None @@ -573,7 +584,8 @@ else: guard_op = self.replace_op_with(op, op.getopnum()) if (self._last_guard_op and guard_op.getdescr() is None and - guard_op.getopnum() != rop.GUARD_VALUE): + guard_op.getopnum() != rop.GUARD_VALUE and + not guard_op.same_guard_position(self._last_guard_op)): op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: @@ -599,6 +611,8 @@ guard_op.setdescr(descr) descr.store_final_boxes(guard_op, last_guard_op.getfailargs(), self.metainterp_sd) + descr.rd_origin_jitcode = guard_op.rd_frame_info_list.jitcode + descr.rd_origin_pc = guard_op.rd_frame_info_list.pc if guard_op.getopnum() == rop.GUARD_VALUE: guard_op = self._maybe_replace_guard_value(guard_op, descr) return guard_op diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -223,12 +223,14 @@ return label_vs def optimize_bridge(self, start_label, operations, call_pure_results, - inline_short_preamble, box_names_memo): + inline_short_preamble, box_names_memo, + origin_jitcode=None, origin_pc=0): self._check_no_forwarding([start_label.getarglist(), operations]) info, ops = self.optimizer.propagate_all_forward( start_label.getarglist()[:], operations[:-1], - call_pure_results, True) + call_pure_results, True, origin_jitcode=origin_jitcode, + origin_pc=origin_pc) jump_op = operations[-1] cell_token = jump_op.getdescr() assert isinstance(cell_token, JitCellToken) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -378,6 +378,13 @@ newop.rd_frame_info_list = self.rd_frame_info_list return newop + def same_guard_position(self, other): + assert isinstance(other, GuardResOp) + frame_info1 = self.rd_frame_info_list + frame_info2 = other.rd_frame_info_list + return (frame_info1.jitcode is frame_info2.jitcode and + frame_info1.pc == frame_info2.pc) + # =========== # type mixins # =========== diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1090,5 +1090,23 @@ self.meta_interp(f, [30]) self.check_trace_count(3) + def test_sharing_guards(self): + driver = JitDriver(greens = [], reds = 'auto') + + def f(i): + s = 0 + while i > 0: + driver.jit_merge_point() + if s > 100: + raise Exception + if s > 9: + s += 1 # bridge + s += 1 + i -= 1 + + self.meta_interp(f, [15]) + # one guard_false got removed + self.check_resops(guard_false=4, guard_true=5) + class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Thu Sep 17 19:21:23 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 19:21:23 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix rpython Message-ID: <20150917172123.1F93B1C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79676:fe7e1a6bc685 Date: 2015-09-17 19:21 +0200 http://bitbucket.org/pypy/pypy/changeset/fe7e1a6bc685/ Log: fix rpython 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 @@ -611,6 +611,7 @@ guard_op.setdescr(descr) descr.store_final_boxes(guard_op, last_guard_op.getfailargs(), self.metainterp_sd) + assert isinstance(guard_op, GuardResOp) descr.rd_origin_jitcode = guard_op.rd_frame_info_list.jitcode descr.rd_origin_pc = guard_op.rd_frame_info_list.pc if guard_op.getopnum() == rop.GUARD_VALUE: From noreply at buildbot.pypy.org Thu Sep 17 19:46:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 19:46:54 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix rpython again Message-ID: <20150917174654.47AEC1C0148@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79677:e05368eee9dd Date: 2015-09-17 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/e05368eee9dd/ Log: fix rpython again diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -696,6 +696,9 @@ status = r_uint(0) + def get_origin_data(self): + return self.rd_origin_jitcode, self.rd_origin_pc + def copy_all_attributes_from(self, other): assert isinstance(other, ResumeGuardDescr) self.rd_count = other.rd_count @@ -1000,12 +1003,12 @@ return resumedescr class ResumeFromInterpDescr(ResumeDescr): - rd_origin_jitcode = None - rd_origin_pc = 0 - def __init__(self, original_greenkey): self.original_greenkey = original_greenkey + def get_origin_data(self): + return None, 0 + def compile_and_attach(self, metainterp, new_loop, orig_inputargs): # We managed to create a bridge going from the interpreter # to previously-compiled code. We keep 'new_loop', which is not @@ -1051,19 +1054,20 @@ call_pure_results = metainterp.call_pure_results + origin_jitcode, origin_pc = resumekey.get_origin_data() if operations[-1].getopnum() == rop.JUMP: data = BridgeCompileData(label, operations[:], call_pure_results=call_pure_results, enable_opts=enable_opts, inline_short_preamble=inline_short_preamble, - origin_jitcode=resumekey.rd_origin_jitcode, - origin_pc=resumekey.rd_origin_pc) + origin_jitcode=origin_jitcode, + origin_pc=origin_pc) else: data = SimpleCompileData(label, operations[:], call_pure_results=call_pure_results, enable_opts=enable_opts, - origin_jitcode=resumekey.rd_origin_jitcode, - origin_pc=resumekey.rd_origin_pc) + origin_jitcode=origin_jitcode, + origin_pc=origin_pc) try: info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) From noreply at buildbot.pypy.org Thu Sep 17 19:53:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 17 Sep 2015 19:53:31 +0200 (CEST) Subject: [pypy-commit] pypy default: Bug! Message-ID: <20150917175331.7C7451C0933@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79678:69e036ea6be6 Date: 2015-09-17 19:53 +0200 http://bitbucket.org/pypy/pypy/changeset/69e036ea6be6/ Log: Bug! diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -5000,3 +5000,56 @@ ]: self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void') assert self.guard_failed == (not is_subclass) + + def test_bug_from_optimize_cond_call(self): + loop = parse(""" + [i0, i1] + i99 = int_sub(i0, i0) + force_spill(i99) + i2 = int_add(i0, i1) + i3 = int_add(i0, i1) + i4 = int_add(i0, i1) + i5 = int_add(i0, i1) + i6 = int_add(i0, i1) + i7 = int_add(i0, i1) + i8 = int_add(i0, i1) + i9 = int_add(i0, i1) + i10 = int_add(i0, i1) + i11 = int_add(i0, i1) + i12 = int_add(i0, i1) + i13 = int_add(i0, i1) + i14 = int_add(i0, i1) + i15 = int_add(i0, i1) + i16 = int_add(i0, i1) + i17 = int_add(i0, i1) + i18 = int_add(i0, i1) + i19 = int_add(i0, i1) + i20 = int_is_true(i99) + force_spill(i0) + force_spill(i1) + force_spill(i2) + force_spill(i3) + force_spill(i4) + force_spill(i5) + force_spill(i6) + force_spill(i7) + force_spill(i8) + force_spill(i9) + force_spill(i10) + force_spill(i11) + force_spill(i12) + force_spill(i13) + force_spill(i14) + force_spill(i15) + force_spill(i16) + force_spill(i17) + force_spill(i18) + force_spill(i19) + finish(i20, descr=finaldescr) + """, namespace={"finaldescr": BasicFinalDescr(1)}) + looptoken = JitCellToken() + self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) + deadframe = self.cpu.execute_token(looptoken, 40, 2) + fail = self.cpu.get_latest_descr(deadframe) + res = self.cpu.get_int_value(deadframe, 0) + assert res == 0 From noreply at buildbot.pypy.org Thu Sep 17 20:09:04 2015 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 17 Sep 2015 20:09:04 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: oops Message-ID: <20150917180904.8D3741C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79679:caf292eb818c Date: 2015-09-17 20:09 +0200 http://bitbucket.org/pypy/pypy/changeset/caf292eb818c/ Log: oops 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 @@ -573,6 +573,7 @@ self.origin_jitcode = None self.origin_pc = 0 else: + self._really_emitted_operation = None # removed return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields From noreply at buildbot.pypy.org Thu Sep 17 20:09:37 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 17 Sep 2015 20:09:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the bug by removing possibly_free_vars() before Message-ID: <20150917180937.1DE881C043B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79680:3d4cfb56c6d1 Date: 2015-09-17 20:09 +0200 http://bitbucket.org/pypy/pypy/changeset/3d4cfb56c6d1/ Log: Fix the bug by removing possibly_free_vars() before force_allocate_reg_or_cc(), which doesn't change anything in the common case where force_allocate_reg_or_cc() would allocate the cc diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -567,7 +567,6 @@ pass else: arglocs[0] = self.rm.make_sure_var_in_reg(vx) - self.possibly_free_vars(args) loc = self.force_allocate_reg_or_cc(op) self.perform(op, arglocs, loc) @@ -605,7 +604,6 @@ arglocs[1] = self.xrm.make_sure_var_in_reg(vy) else: arglocs[0] = self.xrm.make_sure_var_in_reg(vx) - self.possibly_free_vars(op.getarglist()) loc = self.force_allocate_reg_or_cc(op) self.perform(op, arglocs, loc) @@ -1154,7 +1152,6 @@ def consider_int_is_true(self, op): # doesn't need arg to be in a register argloc = self.loc(op.getarg(0)) - self.rm.possibly_free_var(op.getarg(0)) resloc = self.force_allocate_reg_or_cc(op) self.perform(op, [argloc], resloc) From noreply at buildbot.pypy.org Fri Sep 18 08:19:45 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 08:19:45 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: PPC Backend #4: get test_runner fully passing. Message-ID: <20150918061945.D14811C0148@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79681:72dfc868373f Date: 2015-09-14 10:45 +0200 http://bitbucket.org/pypy/pypy/changeset/72dfc868373f/ Log: PPC Backend #4: get test_runner fully passing. Fix many details, remove old code, etc. diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -59,6 +59,7 @@ 'x86': MODEL_X86, # Apple 'Power Macintosh': MODEL_PPC_64, 'ppc64': MODEL_PPC_64, + 'ppc64le': MODEL_PPC_64, 'x86_64': MODEL_X86, 'amd64': MODEL_X86, # freebsd 'AMD64': MODEL_X86, # win64 diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -213,6 +213,23 @@ self.mc.get_relative_pos()) def call_assembler(self, op, argloc, vloc, result_loc, tmploc): + """ + * argloc: location of the frame argument that we're passing to + the called assembler (this is the first return value + of locs_for_call_assembler()) + + * vloc: location of the virtualizable (not in a register; + this is the optional second return value of + locs_for_call_assembler(), or imm(0) if none returned) + + * result_loc: location of op.result (which is not be + confused with the next one) + + * tmploc: location where the actual call to the other piece + of assembler will return its jitframe result + (which is always a REF), before the helper may be + called + """ descr = op.getdescr() assert isinstance(descr, JitCellToken) # diff --git a/rpython/jit/backend/ppc/_flush_icache.c b/rpython/jit/backend/ppc/_flush_icache.c deleted file mode 100644 --- a/rpython/jit/backend/ppc/_flush_icache.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include "../../../translator/c/src/asm_ppc.h" - -static PyObject* -_flush_icache(PyObject *self, PyObject *args) -{ - long base, size; - - if (!PyArg_ParseTuple(args, "ii:_flush_icache", &base, &size)) - return NULL; - - LL_flush_icache(base, size); - Py_INCREF(Py_None); - return Py_None; -} - -PyMethodDef _flush_icache_methods[] = { - {"_flush_icache", _flush_icache, METH_VARARGS, ""}, - {0, 0} -}; - -PyMODINIT_FUNC -init_flush_icache(void) -{ - Py_InitModule("_flush_icache", _flush_icache_methods); -} diff --git a/rpython/jit/backend/ppc/_ppcgen.c b/rpython/jit/backend/ppc/_ppcgen.c deleted file mode 100644 --- a/rpython/jit/backend/ppc/_ppcgen.c +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include - -#define __dcbf(base, index) \ - __asm__ ("dcbf %0, %1" : /*no result*/ : "b%" (index), "r" (base) : "memory") - - -static PyTypeObject* mmap_type; - -#if defined(__APPLE__) - -#include - -static PyObject* -_ppy_NSLookupAndBindSymbol(PyObject* self, PyObject* args) -{ - char *s; - NSSymbol sym; - - if (!PyArg_ParseTuple(args, "s", &s)) - return NULL; - - if (!NSIsSymbolNameDefined(s)) { - return PyErr_Format(PyExc_ValueError, - "symbol '%s' not found", s); - } - - sym = NSLookupAndBindSymbol(s); - - return PyInt_FromLong((long)NSAddressOfSymbol(sym)); -} - - -#elif defined(linux) - -#include - -static PyObject* -_ppy_dlsym(PyObject* self, PyObject* args) -{ - char *s; - void *handle; - void *sym; - - if (!PyArg_ParseTuple(args, "s", &s)) - return NULL; - - handle = dlopen(RTLD_DEFAULT, RTLD_LAZY); - sym = dlsym(handle, s); - if (sym == NULL) { - return PyErr_Format(PyExc_ValueError, - "symbol '%s' not found", s); - } - return PyInt_FromLong((long)sym); -} - -#else - -#error "OS not supported" - -#endif - - -static PyObject* -_ppy_mmap_exec(PyObject* self, PyObject* args) -{ - PyObject* code_args; - PyObject* r; - PyObject* mmap_obj; - char* code; - size_t size; - - if (!PyArg_ParseTuple(args, "O!O!:mmap_exec", - mmap_type, &mmap_obj, - &PyTuple_Type, &code_args)) - return NULL; - - code = *((char**)mmap_obj + 2); - size = *((size_t*)mmap_obj + 3); - - r = ((PyCFunction)code)(NULL, code_args); - - Py_DECREF(args); - - return r; -} - -static PyObject* -_ppy_mmap_flush(PyObject* self, PyObject* arg) -{ - char* code; - size_t size; - int i = 0; - - if (!PyObject_TypeCheck(arg, mmap_type)) { - PyErr_SetString(PyExc_TypeError, - "mmap_flush: single argument must be mmap object"); - } - - code = *((char**)arg + 2); - size = *((size_t*)arg + 3); - - for (; i < size; i += 32){ - __dcbf(code, i); - } - - Py_INCREF(Py_None); - return Py_None; -} - - -PyMethodDef _ppy_methods[] = { -#if defined(__APPLE__) - {"NSLookupAndBindSymbol", _ppy_NSLookupAndBindSymbol, - METH_VARARGS, ""}, -#elif defined(linux) - {"dlsym", _ppy_dlsym, METH_VARARGS, ""}, -#endif - {"mmap_exec", _ppy_mmap_exec, METH_VARARGS, ""}, - {"mmap_flush", _ppy_mmap_flush, METH_O, ""}, - {0, 0} -}; - -#if !defined(MAP_ANON) && defined(__APPLE__) -#define MAP_ANON 0x1000 -#endif - -PyMODINIT_FUNC -init_ppcgen(void) -{ - PyObject* m; - PyObject* mmap_module; - PyObject* mmap_func; - PyObject* mmap_obj; - - m = Py_InitModule("_ppcgen", _ppy_methods); - - /* argh */ - /* time to campaign for a C API for the mmap module! */ - mmap_module = PyImport_ImportModule("mmap"); - if (!mmap_module) - return; - mmap_func = PyObject_GetAttrString(mmap_module, "mmap"); - if (!mmap_func) - return; - mmap_obj = PyEval_CallFunction(mmap_func, "iii", -1, 0, MAP_ANON); - if (!mmap_obj) - return; - mmap_type = mmap_obj->ob_type; - Py_INCREF(mmap_type); - Py_DECREF(mmap_obj); - Py_DECREF(mmap_func); - Py_DECREF(mmap_module); -} diff --git a/rpython/jit/backend/ppc/callbuilder.py b/rpython/jit/backend/ppc/callbuilder.py --- a/rpython/jit/backend/ppc/callbuilder.py +++ b/rpython/jit/backend/ppc/callbuilder.py @@ -214,7 +214,7 @@ # replace b1_location with BEQ(here) jmp_target = self.mc.currpos() pmc = OverwritingBuilder(self.mc, b1_location, 1) - pmc.bc(12, 2, jmp_target - b1_location) # "beq" + pmc.beq(jmp_target - b1_location) pmc.overwrite() if not we_are_translated(): # for testing: now we can access diff --git a/rpython/jit/backend/ppc/codebuilder.py b/rpython/jit/backend/ppc/codebuilder.py --- a/rpython/jit/backend/ppc/codebuilder.py +++ b/rpython/jit/backend/ppc/codebuilder.py @@ -16,6 +16,14 @@ from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.jit.backend.ppc.rassemblermaker import make_rassembler + +# these are the *forbidden* encodings that don't accept register r0: +# addi rX, r0, immed +# subi rX, r0, immed +# addis rX, r0, immed +# subis rX, r0, immed + + A = Form("frD", "frA", "frB", "XO3", "Rc") A1 = Form("frD", "frB", "XO3", "Rc") A2 = Form("frD", "frA", "frC", "XO3", "Rc") @@ -910,30 +918,27 @@ def high(w): return (w >> 16) & 0x0000FFFF -# XXX check this -if we_are_translated(): - eci = ExternalCompilationInfo(includes = ['asm_ppc.h']) +_eci = ExternalCompilationInfo(post_include_bits=[ + '#define rpython_flush_icache() asm("isync":::"memory")\n' + ]) +flush_icache = rffi.llexternal( + "rpython_flush_icache", + [], + lltype.Void, + compilation_info=_eci, + _nowrapper=True, + sandboxsafe=True) - flush_icache = rffi.llexternal( - "LL_flush_icache", - [lltype.Signed, lltype.Signed], - lltype.Void, - compilation_info=eci, - _nowrapper=True, - sandboxsafe=True) -else: - def flush_icache(x, y): pass class PPCGuardToken(GuardToken): def __init__(self, cpu, gcmap, descr, failargs, faillocs, exc, frame_depth, is_guard_not_invalidated=False, is_guard_not_forced=False, fcond=c.cond_none): - assert fcond != c.cond_none GuardToken.__init__(self, cpu, gcmap, descr, failargs, faillocs, exc, frame_depth, is_guard_not_invalidated, is_guard_not_forced) self.fcond = fcond - #self.offset = offset + class OverwritingBuilder(PPCAssembler): def __init__(self, mc, start, num_insts=0): @@ -1205,14 +1210,10 @@ def currpos(self): return self.get_relative_pos() - def flush_cache(self, addr): - startaddr = rffi.cast(lltype.Signed, addr) - size = rffi.cast(lltype.Signed, self.get_relative_pos()) - flush_icache(startaddr, size) - def copy_to_raw_memory(self, addr): self._copy_to_raw_memory(addr) - self.flush_cache(addr) + if we_are_translated(): + flush_icache() self._dump(addr, "jit-backend-dump", 'ppc') def cmp_op(self, block, a, b, imm=False, signed=True, fp=False): diff --git a/rpython/jit/backend/ppc/opassembler.py b/rpython/jit/backend/ppc/opassembler.py --- a/rpython/jit/backend/ppc/opassembler.py +++ b/rpython/jit/backend/ppc/opassembler.py @@ -6,7 +6,9 @@ from rpython.jit.backend.ppc.locations import imm as make_imm_loc from rpython.jit.backend.ppc.arch import (IS_PPC_32, IS_PPC_64, WORD, MAX_REG_PARAMS, MAX_FREG_PARAMS, - PARAM_SAVE_AREA_OFFSET) + PARAM_SAVE_AREA_OFFSET, + THREADLOCAL_ADDR_OFFSET, + IS_BIG_ENDIAN) from rpython.jit.metainterp.history import (JitCellToken, TargetToken, Box, AbstractFailDescr, FLOAT, INT, REF) @@ -22,6 +24,7 @@ from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref from rpython.jit.metainterp.resoperation import rop +from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.backend.ppc import callbuilder class IntOpAssembler(object): @@ -209,7 +212,7 @@ l0, res = arglocs self.mc.fabs(res.value, l0.value) - def emit_math_sqrt(self, op, arglocs, regalloc): + def _emit_math_sqrt(self, op, arglocs, regalloc): l0, res = arglocs self.mc.fsqrt(res.value, l0.value) @@ -320,7 +323,7 @@ self.mc.trap() self._cmp_guard_class(op, arglocs, regalloc) pmc = OverwritingBuilder(self.mc, patch_pos, 1) - pmc.bc(12, 0, self.mc.currpos() - patch_pos) # LT + pmc.blt(self.mc.currpos() - patch_pos) pmc.overwrite() self.guard_success_cc = c.EQ self._emit_guard(op, arglocs[3:]) @@ -355,6 +358,13 @@ self.guard_success_cc = c.EQ self._emit_guard(op, arglocs) + def emit_guard_not_forced_2(self, op, arglocs, regalloc): + guard_token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], + c.cond_none, save_exc=False) + self._finish_gcmap = guard_token.gcmap + self._store_force_index(op) + self.store_info_on_descr(0, guard_token) + class MiscOpAssembler(object): @@ -448,6 +458,8 @@ pmc.overwrite() def emit_guard_exception(self, op, arglocs, regalloc): + # XXX FIXME + # XXX pos_exc_value and pos_exception are 8 bytes apart, don't need both loc, loc1, resloc, pos_exc_value, pos_exception = arglocs[:5] failargs = arglocs[5:] self.mc.load_imm(loc1, pos_exception.value) @@ -490,6 +502,9 @@ cb.emit() def emit_call(self, op, arglocs, regalloc): + oopspecindex = regalloc.get_oopspecindex(op) + if oopspecindex == EffectInfo.OS_MATH_SQRT: + return self._emit_math_sqrt(op, arglocs, regalloc) self._emit_call(op, arglocs) def emit_call_may_force(self, op, arglocs, regalloc): @@ -832,7 +847,7 @@ if jz_location != -1: pmc = OverwritingBuilder(self.mc, jz_location, 1) - pmc.bc(4, 1, self.mc.currpos() - jz_location) # !GT + pmc.ble(self.mc.currpos() - jz_location) # !GT pmc.overwrite() class StrOpAssembler(object): @@ -843,118 +858,61 @@ emit_strgetitem = FieldOpAssembler.emit_getarrayitem_gc emit_strsetitem = FieldOpAssembler.emit_setarrayitem_gc - #from ../x86/regalloc.py:928 ff. def emit_copystrcontent(self, op, arglocs, regalloc): - assert len(arglocs) == 0 - self._emit_copystrcontent(op, regalloc, is_unicode=False) + self._emit_copycontent(arglocs, is_unicode=False) def emit_copyunicodecontent(self, op, arglocs, regalloc): - assert len(arglocs) == 0 - self._emit_copystrcontent(op, regalloc, is_unicode=True) + self._emit_copycontent(arglocs, is_unicode=True) - def _emit_copystrcontent(self, op, regalloc, is_unicode): - # compute the source address - args = op.getarglist() - base_loc = regalloc._ensure_value_is_boxed(args[0], args) - ofs_loc = regalloc._ensure_value_is_boxed(args[2], args) - assert args[0] is not args[1] # forbidden case of aliasing - regalloc.possibly_free_var(args[0]) - if args[3] is not args[2] is not args[4]: # MESS MESS MESS: don't free - regalloc.possibly_free_var(args[2]) # it if ==args[3] or args[4] - srcaddr_box = TempPtr() - forbidden_vars = [args[1], args[3], args[4], srcaddr_box] - srcaddr_loc = regalloc.force_allocate_reg(srcaddr_box) - self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc, - is_unicode=is_unicode) + def _emit_load_for_copycontent(self, dst, src_ptr, src_ofs, scale): + if src_ofs.is_imm(): + value = src_ofs.value << scale + if value < 32768: + self.mc.addi(dst.value, src_ptr.value, value) + else: + self.mc.load_imm(dst, value) + self.mc.add(dst.value, src_ptr.value, dst.value) + elif scale == 0: + self.mc.add(dst.value, src_ptr.value, src_ofs.value) + else: + self.mc.sldi(dst.value, src_ofs.value, scale) + self.mc.add(dst.value, src_ptr.value, dst.value) - # compute the destination address - forbidden_vars = [args[4], args[3], srcaddr_box] - dstaddr_box = TempPtr() - dstaddr_loc = regalloc.force_allocate_reg(dstaddr_box) - forbidden_vars.append(dstaddr_box) - base_loc = regalloc._ensure_value_is_boxed(args[1], forbidden_vars) - ofs_loc = regalloc._ensure_value_is_boxed(args[3], forbidden_vars) - assert base_loc.is_reg() - assert ofs_loc.is_reg() - regalloc.possibly_free_var(args[1]) - if args[3] is not args[4]: # more of the MESS described above - regalloc.possibly_free_var(args[3]) - regalloc.free_temp_vars() - self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc, - is_unicode=is_unicode) + def _emit_copycontent(self, arglocs, is_unicode): + [src_ptr_loc, dst_ptr_loc, + src_ofs_loc, dst_ofs_loc, length_loc] = arglocs - # compute the length in bytes - forbidden_vars = [srcaddr_box, dstaddr_box] - if isinstance(args[4], Box): - length_box = args[4] - length_loc = regalloc.make_sure_var_in_reg(args[4], forbidden_vars) + if is_unicode: + basesize, itemsize, _ = symbolic.get_array_token(rstr.UNICODE, + self.cpu.translate_support_code) + if itemsize == 2: scale = 1 + elif itemsize == 4: scale = 2 + else: raise AssertionError else: - length_box = TempInt() - length_loc = regalloc.force_allocate_reg(length_box, forbidden_vars) - xxxxxxxxxxxxxxxxxxxxxxxx - imm = regalloc.convert_to_imm(args[4]) - self.load(length_loc, imm) - if is_unicode: - bytes_box = TempPtr() - bytes_loc = regalloc.force_allocate_reg(bytes_box, forbidden_vars) - scale = self._get_unicode_item_scale() - assert length_loc.is_reg() - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, 1 << scale) - if IS_PPC_32: - self.mc.mullw(bytes_loc.value, r.SCRATCH.value, length_loc.value) - else: - self.mc.mulld(bytes_loc.value, r.SCRATCH.value, length_loc.value) - length_box = bytes_box - length_loc = bytes_loc - # call memcpy() - regalloc.before_call() - imm_addr = make_imm_loc(self.memcpy_addr) - self._emit_call(imm_addr, - [dstaddr_loc, srcaddr_loc, length_loc]) - - regalloc.possibly_free_var(length_box) - regalloc.possibly_free_var(dstaddr_box) - regalloc.possibly_free_var(srcaddr_box) - - def _gen_address_inside_string(self, baseloc, ofsloc, resloc, is_unicode): - if is_unicode: - ofs_items, _, _ = symbolic.get_array_token(rstr.UNICODE, - self.cpu.translate_support_code) - scale = self._get_unicode_item_scale() - else: - ofs_items, itemsize, _ = symbolic.get_array_token(rstr.STR, - self.cpu.translate_support_code) + basesize, itemsize, _ = symbolic.get_array_token(rstr.STR, + self.cpu.translate_support_code) assert itemsize == 1 scale = 0 - self._gen_address(ofsloc, ofs_items, scale, resloc, baseloc) - def _gen_address(self, sizereg, baseofs, scale, result, baseloc=None): - assert sizereg.is_reg() - if scale > 0: - scaled_loc = r.r0 - if IS_PPC_32: - self.mc.slwi(scaled_loc.value, sizereg.value, scale) - else: - self.mc.sldi(scaled_loc.value, sizereg.value, scale) + self._emit_load_for_copycontent(r.r0, src_ptr_loc, src_ofs_loc, scale) + self._emit_load_for_copycontent(r.r2, dst_ptr_loc, dst_ofs_loc, scale) + + if length_loc.is_imm(): + length = length_loc.getint() + self.mc.load_imm(r.r5, length << scale) else: - scaled_loc = sizereg - if baseloc is not None: - assert baseloc.is_reg() - self.mc.add(result.value, baseloc.value, scaled_loc.value) - self.mc.addi(result.value, result.value, baseofs) - else: - self.mc.addi(result.value, scaled_loc.value, baseofs) + if scale > 0: + self.mc.sldi(r.r5.value, length_loc.value, scale) + elif length_loc is not r.r5: + self.mc.mr(r.r5.value, length_loc.value) - def _get_unicode_item_scale(self): - _, itemsize, _ = symbolic.get_array_token(rstr.UNICODE, - self.cpu.translate_support_code) - if itemsize == 4: - return 2 - elif itemsize == 2: - return 1 - else: - raise AssertionError("bad unicode item size") + self.mc.mr(r.r4.value, r.r0.value) + self.mc.addi(r.r4.value, r.r4.value, basesize) + self.mc.addi(r.r3.value, r.r2.value, basesize) + + cb = callbuilder.CallBuilder(self, imm(self.memcpy_addr), + [r.r3, r.r4, r.r5], None) + cb.emit() class UnicodeOpAssembler(object): @@ -991,135 +949,142 @@ emit_jit_debug = emit_debug_merge_point emit_keepalive = emit_debug_merge_point - def emit_cond_call_gc_wb(self, op, arglocs, regalloc): + def _write_barrier_fastpath(self, mc, descr, arglocs, regalloc, array=False, + is_frame=False, align_stack=False): # Write code equivalent to write_barrier() in the GC: it checks - # a flag in the object at arglocs[0], and if set, it calls the - # function remember_young_pointer() from the GC. The two arguments - # to the call are in arglocs[:2]. The latter saves registers as needed - # and call the function jit_remember_young_pointer() from the GC. - descr = op.getdescr() + # a flag in the object at arglocs[0], and if set, it calls a + # helper piece of assembler. The latter saves registers as needed + # and call the function remember_young_pointer() from the GC. if we_are_translated(): cls = self.cpu.gc_ll_descr.has_write_barrier_class() assert cls is not None and isinstance(descr, cls) # - opnum = op.getopnum() - card_marking = False + card_marking_mask = 0 mask = descr.jit_wb_if_flag_singlebyte - if opnum == rop.COND_CALL_GC_WB_ARRAY and descr.jit_wb_cards_set != 0: + if array and descr.jit_wb_cards_set != 0: # assumptions the rest of the function depends on: assert (descr.jit_wb_cards_set_byteofs == descr.jit_wb_if_flag_byteofs) - assert descr.jit_wb_cards_set_singlebyte == -0x80 - card_marking = True - mask = descr.jit_wb_if_flag_singlebyte | -0x80 + card_marking_mask = descr.jit_wb_cards_set_singlebyte # loc_base = arglocs[0] + assert loc_base.is_reg() + if is_frame: + assert loc_base is r.SPP assert _check_imm_arg(descr.jit_wb_if_flag_byteofs) - with scratch_reg(self.mc): - self.mc.lbz(r.SCRATCH.value, loc_base.value, - descr.jit_wb_if_flag_byteofs) - # test whether this bit is set - mask &= 0xFF - self.mc.andix(r.SCRATCH.value, r.SCRATCH.value, mask) + mc.lbz(r.SCRATCH2.value, loc_base.value, descr.jit_wb_if_flag_byteofs) + mc.andix(r.SCRATCH.value, r.SCRATCH2.value, mask & 0xFF) - jz_location = self.mc.currpos() - self.mc.nop() + jz_location = mc.get_relative_pos() + mc.trap() # patched later with 'beq' # for cond_call_gc_wb_array, also add another fast path: # if GCFLAG_CARDS_SET, then we can just set one bit and be done - if card_marking: - with scratch_reg(self.mc): - self.mc.lbz(r.SCRATCH.value, loc_base.value, - descr.jit_wb_if_flag_byteofs) - self.mc.extsb(r.SCRATCH.value, r.SCRATCH.value) - - # test whether this bit is set - self.mc.cmpwi(0, r.SCRATCH.value, 0) - - js_location = self.mc.currpos() - self.mc.nop() + if card_marking_mask: + # GCFLAG_CARDS_SET is in the same byte, loaded in r2 already + mc.andix(r.SCRATCH.value, r.SCRATCH2.value, + card_marking_mask & 0xFF) + js_location = mc.get_relative_pos() + mc.trap() # patched later with 'bne' else: js_location = 0 # Write only a CALL to the helper prepared in advance, passing it as # argument the address of the structure we are writing into # (the first argument to COND_CALL_GC_WB). - helper_num = card_marking - - if self._regalloc.fprm.reg_bindings: + helper_num = (card_marking_mask != 0) + if is_frame: + helper_num = 4 + elif regalloc.fprm.reg_bindings: helper_num += 2 if self.wb_slowpath[helper_num] == 0: # tests only assert not we_are_translated() self.cpu.gc_ll_descr.write_barrier_descr = descr - self._build_wb_slowpath(card_marking, - bool(self._regalloc.fprm.reg_bindings)) + self._build_wb_slowpath(card_marking_mask != 0, + bool(regalloc.fprm.reg_bindings)) assert self.wb_slowpath[helper_num] != 0 # - if loc_base is not r.r3: - self.mc.store(r.r3.value, r.SP.value, 24) - remap_frame_layout(self, [loc_base], [r.r3], r.SCRATCH) - addr = self.wb_slowpath[helper_num] - func = rffi.cast(lltype.Signed, addr) - self.mc.bl_abs(func) - if loc_base is not r.r3: - self.mc.load(r.r3.value, r.SP.value, 24) + if not is_frame: + mc.mr(r.r0.value, loc_base.value) # unusual argument location + if is_frame and align_stack: + XXXX + mc.SUB_ri(esp.value, 16 - WORD) # erase the return address + mc.load_imm(r.SCRATCH2, self.wb_slowpath[helper_num]) + mc.mtctr(r.SCRATCH2.value) + mc.bctrl() + if is_frame and align_stack: + XXXX + mc.ADD_ri(esp.value, 16 - WORD) # erase the return address - # if GCFLAG_CARDS_SET, then we can do the whole thing that would - # be done in the CALL above with just four instructions, so here - # is an inline copy of them - if card_marking: - with scratch_reg(self.mc): - jns_location = self.mc.currpos() - self.mc.nop() # jump to the exit, patched later - # patch the JS above - offset = self.mc.currpos() - pmc = OverwritingBuilder(self.mc, js_location, 1) - # Jump if JS comparison is less than (bit set) - pmc.bc(12, 0, offset - js_location) - pmc.overwrite() - # - # case GCFLAG_CARDS_SET: emit a few instructions to do - # directly the card flag setting - loc_index = arglocs[1] - assert loc_index.is_reg() - tmp1 = arglocs[-1] - tmp2 = arglocs[-2] - tmp3 = arglocs[-3] - #byteofs - s = 3 + descr.jit_wb_card_page_shift + if card_marking_mask: + # The helper ends again with a check of the flag in the object. + # So here, we can simply write again a beq, which will be + # taken if GCFLAG_CARDS_SET is still not set. + jns_location = mc.get_relative_pos() + mc.trap() + # + # patch the 'bne' above + currpos = mc.currpos() + pmc = OverwritingBuilder(mc, js_location, 1) + pmc.bne(currpos - js_location) + pmc.overwrite() + # + # case GCFLAG_CARDS_SET: emit a few instructions to do + # directly the card flag setting + loc_index = arglocs[1] + if loc_index.is_reg(): - self.mc.srli_op(tmp3.value, loc_index.value, s) - self.mc.not_(tmp3.value, tmp3.value) + tmp_loc = arglocs[2] + n = descr.jit_wb_card_page_shift - # byte_index - self.mc.li(r.SCRATCH.value, 7) - self.mc.srli_op(loc_index.value, loc_index.value, - descr.jit_wb_card_page_shift) - self.mc.and_(tmp1.value, r.SCRATCH.value, loc_index.value) + # compute in tmp_loc the byte offset: + # ~(index >> (card_page_shift + 3)) ('~' is 'not_' below) + mc.srli_op(tmp_loc.value, loc_index.value, n + 3) - # set the bit - self.mc.li(tmp2.value, 1) - self.mc.lbzx(r.SCRATCH.value, loc_base.value, tmp3.value) - self.mc.sl_op(tmp2.value, tmp2.value, tmp1.value) - self.mc.or_(r.SCRATCH.value, r.SCRATCH.value, tmp2.value) - self.mc.stbx(r.SCRATCH.value, loc_base.value, tmp3.value) + # compute in r2 the index of the bit inside the byte: + # (index >> card_page_shift) & 7 + mc.rldicl(r.SCRATCH2.value, loc_index.value, 64 - n, 61) + mc.li(r.SCRATCH.value, 1) + mc.not_(tmp_loc.value, tmp_loc.value) + + # set r2 to 1 << r2 + mc.sl_op(r.SCRATCH2.value, r.SCRATCH.value, r.SCRATCH2.value) + + # set this bit inside the byte of interest + mc.lbzx(r.SCRATCH.value, loc_base.value, tmp_loc.value) + mc.or_(r.SCRATCH.value, r.SCRATCH.value, r.SCRATCH2.value) + mc.stbx(r.SCRATCH.value, loc_base.value, tmp_loc.value) # done - # patch the JNS above - offset = self.mc.currpos() - pmc = OverwritingBuilder(self.mc, jns_location, 1) - # Jump if JNS comparison is not less than (bit not set) - pmc.bc(4, 0, offset - jns_location) - pmc.overwrite() + else: + byte_index = loc_index.value >> descr.jit_wb_card_page_shift + byte_ofs = ~(byte_index >> 3) + byte_val = 1 << (byte_index & 7) + assert _check_imm_arg(byte_ofs) + + mc.lbz(r.SCRATCH.value, loc_base.value, byte_ofs) + mc.ori(r.SCRATCH.value, r.SCRATCH.value, byte_val) + mc.stb(r.SCRATCH.value, loc_base.value, byte_ofs) + # + # patch the beq just above + currpos = mc.currpos() + pmc = OverwritingBuilder(mc, jns_location, 1) + pmc.beq(currpos - jns_location) + pmc.overwrite() # patch the JZ above - offset = self.mc.currpos() - pmc = OverwritingBuilder(self.mc, jz_location, 1) - # Jump if JZ comparison is zero (CMP 0 is equal) - pmc.bc(12, 2, offset - jz_location) + currpos = mc.currpos() + pmc = OverwritingBuilder(mc, jz_location, 1) + pmc.beq(currpos - jz_location) pmc.overwrite() - emit_cond_call_gc_wb_array = emit_cond_call_gc_wb + def emit_cond_call_gc_wb(self, op, arglocs, regalloc): + self._write_barrier_fastpath(self.mc, op.getdescr(), arglocs, regalloc) + + def emit_cond_call_gc_wb_array(self, op, arglocs, regalloc): + self._write_barrier_fastpath(self.mc, op.getdescr(), arglocs, regalloc, + array=True) + class ForceOpAssembler(object): @@ -1129,215 +1094,95 @@ res_loc = arglocs[0] self.mc.mr(res_loc.value, r.SPP.value) - # self._emit_guard(guard_op, regalloc._prepare_guard(guard_op), c.LT) - # from: ../x86/assembler.py:1668 - # XXX Split into some helper methods - def emit_guard_call_assembler(self, op, guard_op, arglocs, regalloc): - tmploc = arglocs[1] - resloc = arglocs[2] - callargs = arglocs[3:] + def emit_call_assembler(self, op, arglocs, regalloc): + if len(arglocs) == 3: + [result_loc, argloc, vloc] = arglocs + else: + [result_loc, argloc] = arglocs + vloc = imm(0) + self._store_force_index(self._find_nearby_operation(regalloc, +1)) + # 'result_loc' is either r3 or f1 + self.call_assembler(op, argloc, vloc, result_loc, r.r3) - faildescr = guard_op.getdescr() - fail_index = self.cpu.get_fail_descr_number(faildescr) - self._write_fail_index(fail_index) - descr = op.getdescr() - assert isinstance(descr, JitCellToken) - # check value - assert tmploc is r.RES - xxxxxxxxxxxx - self._emit_call(fail_index, imm(descr._ppc_func_addr), - callargs, result=tmploc) - if op.result is None: - value = self.cpu.done_with_this_frame_void_v + imm = staticmethod(imm) # for call_assembler() + + def _call_assembler_emit_call(self, addr, argloc, _): + self.regalloc_mov(argloc, r.r3) + self.mc.ld(r.r4.value, r.SP.value, THREADLOCAL_ADDR_OFFSET) + + cb = callbuilder.CallBuilder(self, addr, [r.r3, r.r4], r.r3) + cb.emit() + + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + cb = callbuilder.CallBuilder(self, addr, arglocs, result_loc) + cb.emit() + + def _call_assembler_check_descr(self, value, tmploc): + ofs = self.cpu.get_ofs_of_frame_field('jf_descr') + self.mc.ld(r.r5.value, r.r3.value, ofs) + if _check_imm_arg(value): + self.mc.cmp_op(0, r.r5.value, value, imm=True) else: + self.mc.load_imm(r.r4, value) + self.mc.cmp_op(0, r.r5.value, r.r4.value, imm=False) + jump_if_eq = self.mc.currpos() + self.mc.nop() # patched later + return jump_if_eq + + def _call_assembler_patch_je(self, result_loc, je_location): + jump_to_done = self.mc.currpos() + self.mc.nop() # patched later + # + currpos = self.mc.currpos() + pmc = OverwritingBuilder(self.mc, je_location, 1) + pmc.beq(currpos - je_location) + pmc.overwrite() + # + return jump_to_done + + def _call_assembler_load_result(self, op, result_loc): + if op.result is not None: + # load the return value from the dead frame's value index 0 kind = op.result.type - if kind == INT: - value = self.cpu.done_with_this_frame_int_v - elif kind == REF: - value = self.cpu.done_with_this_frame_ref_v - elif kind == FLOAT: - value = self.cpu.done_with_this_frame_float_v + descr = self.cpu.getarraydescr_for_frame(kind) + ofs = self.cpu.unpack_arraydescr(descr) + if kind == FLOAT: + assert result_loc is r.f1 + self.mc.lfd(r.f1.value, r.r3.value, ofs) else: - raise AssertionError(kind) + assert result_loc is r.r3 + self.mc.ld(r.r3.value, r.r3.value, ofs) - # take fast path on equality - # => jump on inequality - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, value) - self.mc.cmp_op(0, tmploc.value, r.SCRATCH.value) - - #if values are equal we take the fast path - # Slow path, calling helper - # jump to merge point - - jd = descr.outermost_jitdriver_sd - assert jd is not None - - # Path A: load return value and reset token - # Fast Path using result boxes - - fast_jump_pos = self.mc.currpos() - self.mc.nop() - - # Reset the vable token --- XXX really too much special logic here:-( - if jd.index_of_virtualizable >= 0: - from pypy.jit.backend.llsupport.descr import FieldDescr - fielddescr = jd.vable_token_descr - assert isinstance(fielddescr, FieldDescr) - ofs = fielddescr.offset - tmploc = regalloc.get_scratch_reg(INT) - with scratch_reg(self.mc): - self.mov_loc_loc(arglocs[0], r.SCRATCH) - self.mc.li(tmploc.value, 0) - self.mc.storex(tmploc.value, 0, r.SCRATCH.value) - - if op.result is not None: - # load the return value from fail_boxes_xxx[0] - kind = op.result.type - if kind == INT: - adr = self.fail_boxes_int.get_addr_for_num(0) - elif kind == REF: - adr = self.fail_boxes_ptr.get_addr_for_num(0) - elif kind == FLOAT: - adr = self.fail_boxes_float.get_addr_for_num(0) - else: - raise AssertionError(kind) - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, adr) - if op.result.type == FLOAT: - self.mc.lfdx(resloc.value, 0, r.SCRATCH.value) - else: - self.mc.loadx(resloc.value, 0, r.SCRATCH.value) - - # jump to merge point, patched later - fast_path_to_end_jump_pos = self.mc.currpos() - self.mc.nop() - - jmp_pos = self.mc.currpos() - pmc = OverwritingBuilder(self.mc, fast_jump_pos, 1) - pmc.bc(4, 2, jmp_pos - fast_jump_pos) + def _call_assembler_patch_jmp(self, jmp_location): + currpos = self.mc.currpos() + pmc = OverwritingBuilder(self.mc, jmp_location, 1) + pmc.b(currpos - jmp_location) pmc.overwrite() - # Path B: use assembler helper - asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr) - if self.cpu.supports_floats: - floats = r.VOLATILES_FLOAT - else: - floats = [] - - with Saved_Volatiles(self.mc, save_RES=False): - # result of previous call is in r3 - self.mov_loc_loc(arglocs[0], r.r4) - self.mc.call(asm_helper_adr) - - # merge point - currpos = self.mc.currpos() - pmc = OverwritingBuilder(self.mc, fast_path_to_end_jump_pos, 1) - pmc.b(currpos - fast_path_to_end_jump_pos) - pmc.overwrite() - - with scratch_reg(self.mc): - self.mc.load(r.SCRATCH.value, r.SPP.value, FORCE_INDEX_OFS) - self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - - self._emit_guard(guard_op, regalloc._prepare_guard(guard_op), - xxxxxxxxxxxxxxxxx+c.LT, save_exc=True) - - # ../x86/assembler.py:668 def redirect_call_assembler(self, oldlooptoken, newlooptoken): # some minimal sanity checking old_nbargs = oldlooptoken.compiled_loop_token._debug_nbargs new_nbargs = newlooptoken.compiled_loop_token._debug_nbargs assert old_nbargs == new_nbargs - oldadr = oldlooptoken._ppc_func_addr - target = newlooptoken._ppc_func_addr - if IS_PPC_32: - # we overwrite the instructions at the old _ppc_func_addr - # to start with a JMP to the new _ppc_func_addr. + oldadr = oldlooptoken._ll_function_addr + target = newlooptoken._ll_function_addr + if IS_PPC_32 or not IS_BIG_ENDIAN: + # we overwrite the instructions at the old _ll_function_addr + # to start with a JMP to the new _ll_function_addr. # Ideally we should rather patch all existing CALLs, but well. mc = PPCBuilder() mc.b_abs(target) mc.copy_to_raw_memory(oldadr) else: - # PPC64 trampolines are data so overwrite the code address - # in the function descriptor at the old address - # (TOC and static chain pointer are the same). + # PPC64 big-endian trampolines are data so overwrite the code + # address in the function descriptor at the old address. + # Copy the whole 3-word trampoline, even though the other + # words are always zero so far. odata = rffi.cast(rffi.CArrayPtr(lltype.Signed), oldadr) tdata = rffi.cast(rffi.CArrayPtr(lltype.Signed), target) odata[0] = tdata[0] - - def emit_guard_call_may_force(self, op, guard_op, arglocs, regalloc): - faildescr = guard_op.getdescr() - fail_index = self.cpu.get_fail_descr_number(faildescr) - self._write_fail_index(fail_index) - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - xxxxxxxxxxxxxx - self._emit_call(fail_index, adr, callargs, resloc, (size, signed)) - - with scratch_reg(self.mc): - self.mc.load(r.SCRATCH.value, r.SPP.value, FORCE_INDEX_OFS) - self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - - self._emit_guard(guard_op, arglocs[1 + numargs:], - xxxxxxxxxxxxxx+c.LT, save_exc=True) - - def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc): - - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - self.call_release_gil(gcrootmap, arglocs) - # do the call - faildescr = guard_op.getdescr() - fail_index = self.cpu.get_fail_descr_number(faildescr) - self._write_fail_index(fail_index) - # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - xxxxxxxxxxxxxxx - self._emit_call(fail_index, adr, callargs, resloc, (size, signed)) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc) - - with scratch_reg(self.mc): - self.mc.load(r.SCRATCH.value, r.SPP.value, 0) - self.mc.cmp_op(0, r.SCRATCH.value, 0, imm=True) - - self._emit_guard(guard_op, arglocs[1 + numargs:], - xxxxxxxxxxxxxxxxxx+c.LT, save_exc=True) - - def call_release_gil(self, gcrootmap, save_registers): - # XXX don't know whether this is correct - # XXX use save_registers here - assert gcrootmap.is_shadow_stack - with Saved_Volatiles(self.mc): - #self._emit_call(NO_FORCE_INDEX, self.releasegil_addr, - # [], self._regalloc) - self._emit_call(imm(self.releasegil_addr), []) - - def call_reacquire_gil(self, gcrootmap, save_loc): - # save the previous result into the stack temporarily. - # XXX like with call_release_gil(), we assume that we don't need - # to save vfp regs in this case. Besides the result location - assert gcrootmap.is_shadow_stack - with Saved_Volatiles(self.mc): - self._emit_call(imm(self.reacqgil_addr), []) + odata[1] = tdata[1] + odata[2] = tdata[2] class OpAssembler(IntOpAssembler, GuardOpAssembler, diff --git a/rpython/jit/backend/ppc/ppc_assembler.py b/rpython/jit/backend/ppc/ppc_assembler.py --- a/rpython/jit/backend/ppc/ppc_assembler.py +++ b/rpython/jit/backend/ppc/ppc_assembler.py @@ -28,7 +28,7 @@ from rpython.rlib.debug import (debug_print, debug_start, debug_stop, have_debug_prints) from rpython.rlib import rgc -from rpython.rtyper.annlowlevel import llhelper +from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.rtyper.lltypesystem.lloperation import llop from rpython.jit.backend.ppc.locations import StackLocation, get_fp_offset, imm @@ -92,8 +92,10 @@ def __init__(self, cpu, translate_support_code=False): BaseAssembler.__init__(self, cpu, translate_support_code) self.loop_run_counters = [] + self.wb_slowpath = [0, 0, 0, 0, 0] self.setup_failure_recovery() self.stack_check_slowpath = 0 + self.propagate_exception_path = 0 self.teardown() def set_debug(self, v): @@ -122,33 +124,6 @@ mc.lfd(reg.value, spp_reg.value, self.OFFSET_SPP_TO_FPR_SAVE_AREA + WORD * i) - # The code generated here allocates a new stackframe - # and is the first machine code to be executed. - def _make_frame(self, frame_depth): - XXX - self.mc.make_function_prologue(frame_depth) - - # save SPP at the bottom of the stack frame - self.mc.store(r.SPP.value, r.SP.value, WORD) - - # compute spilling pointer (SPP) - self.mc.addi(r.SPP.value, r.SP.value, - frame_depth - self.OFFSET_SPP_TO_OLD_BACKCHAIN) - - # save nonvolatile registers - self._save_nonvolatiles() - - # save r31, use r30 as scratch register - # this is safe because r30 has been saved already - assert NONVOLATILES[-1] == r.SPP - ofs_to_r31 = (self.OFFSET_SPP_TO_GPR_SAVE_AREA + - WORD * (len(NONVOLATILES)-1)) - self.mc.load(r.r30.value, r.SP.value, WORD) - self.mc.store(r.r30.value, r.SPP.value, ofs_to_r31) - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap and gcrootmap.is_shadow_stack: - self.gen_shadowstack_header(gcrootmap) - def gen_shadowstack_header(self, gcrootmap): # we need to put two words into the shadowstack: the MARKER_FRAME # and the address of the frame (fp, actually) @@ -296,7 +271,7 @@ self._frame_realloc_slowpath = mc.materialize(self.cpu, []) self.mc = None - def _store_and_reset_exception(self, mc, excvalloc, exctploc): + def _store_and_reset_exception(self, mc, excvalloc, exctploc=None): """Reset the exception, after fetching it inside the two regs. """ mc.load_imm(r.r2, self.cpu.pos_exc_value()) @@ -304,7 +279,8 @@ assert _check_imm_arg(diff) # Load the exception fields into the two registers mc.load(excvalloc.value, r.r2.value, 0) - mc.load(exctploc.value, r.r2.value, diff) + if exctploc is not None: + mc.load(exctploc.value, r.r2.value, diff) # Zero out the exception fields mc.li(r.r0.value, 0) mc.store(r.r0.value, r.r2.value, 0) @@ -359,6 +335,7 @@ return mc.materialize(self.cpu, []) def _build_malloc_slowpath(self): + xxxxxxx mc = PPCBuilder() frame_size = (len(r.MANAGED_FP_REGS) * WORD + (BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) @@ -405,7 +382,7 @@ # if r3 == 0 we skip the return above and jump to the exception path offset = mc.currpos() - jmp_pos pmc = OverwritingBuilder(mc, jmp_pos, 1) - pmc.bc(12, 2, offset) + pmc.beq(offset) pmc.overwrite() # restore the frame before leaving with scratch_reg(mc): @@ -500,7 +477,7 @@ mc.b(self.propagate_exception_path) pmc = OverwritingBuilder(mc, jnz_location, 1) - pmc.bc(4, 2, mc.currpos() - jnz_location) + pmc.bne(mc.currpos() - jnz_location) pmc.overwrite() # restore link register out of preprevious frame @@ -520,7 +497,6 @@ self.write_64_bit_func_descr(rawstart, rawstart+3*WORD) self.stack_check_slowpath = rawstart - # TODO: see what need to be done when for_frame is True def _build_wb_slowpath(self, withcards, withfloats=False, for_frame=False): descr = self.cpu.gc_ll_descr.write_barrier_descr if descr is None: @@ -536,56 +512,108 @@ # # This builds a helper function called from the slow path of # write barriers. It must save all registers, and optionally - # all fp registers. + # all fp registers. It takes its single argument in r0. mc = PPCBuilder() + old_mc = self.mc + self.mc = mc # - frame_size = ((len(r.VOLATILES) + len(r.VOLATILES_FLOAT) - + BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) - mc.make_function_prologue(frame_size) - for i in range(len(r.VOLATILES)): - mc.store(r.VOLATILES[i].value, r.SP.value, - (BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) - if self.cpu.supports_floats: - for i in range(len(r.VOLATILES_FLOAT)): - mc.stfd(r.VOLATILES_FLOAT[i].value, r.SP.value, - (len(r.VOLATILES) + BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) + ignored_regs = [reg for reg in r.MANAGED_REGS if not ( + # 'reg' will be pushed if the following is true: + reg in r.VOLATILES or + reg is r.RCS1 or + (withcards and reg is r.RCS2))] + if not for_frame: + # push all volatile registers, push RCS1, and sometimes push RCS2 + self._push_all_regs_to_jitframe(mc, ignored_regs, withfloats) + else: + return #XXXXX + # we have one word to align + mc.SUB_ri(esp.value, 7 * WORD) # align and reserve some space + mc.MOV_sr(WORD, eax.value) # save for later + if self.cpu.supports_floats: + mc.MOVSD_sx(2 * WORD, xmm0.value) # 32-bit: also 3 * WORD + if IS_X86_32: + mc.MOV_sr(4 * WORD, edx.value) + mc.MOV_sr(0, ebp.value) + exc0, exc1 = esi, edi + else: + mc.MOV_rr(edi.value, ebp.value) + exc0, exc1 = ebx, r12 + mc.MOV(RawEspLoc(WORD * 5, REF), exc0) + mc.MOV(RawEspLoc(WORD * 6, INT), exc1) + # note that it's save to store the exception in register, + # since the call to write barrier can't collect + # (and this is assumed a bit left and right here, like lack + # of _reload_frame_if_necessary) + self._store_and_reset_exception(mc, exc0, exc1) - mc.call(rffi.cast(lltype.Signed, func)) - if self.cpu.supports_floats: - for i in range(len(r.VOLATILES_FLOAT)): - mc.lfd(r.VOLATILES_FLOAT[i].value, r.SP.value, - (len(r.VOLATILES) + BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) - for i in range(len(r.VOLATILES)): - mc.load(r.VOLATILES[i].value, r.SP.value, - (BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) - mc.restore_LR_from_caller_frame(frame_size) + if withcards: + mc.mr(r.RCS2.value, r.r0.value) + # + # Save the lr into r.RCS1 + mc.mflr(r.RCS1.value) + # + func = rffi.cast(lltype.Signed, func) + cb = callbuilder.CallBuilder(self, imm(func), [r.r0], None) + cb.emit() + # + # Restore lr + mc.mtlr(r.RCS1.value) # if withcards: - # A final compare before the RET, for the caller. Careful to + # A final andix before the blr, for the caller. Careful to # not follow this instruction with another one that changes - # the status of the CPU flags! - mc.lbz(r.SCRATCH.value, r.r3.value, - descr.jit_wb_if_flag_byteofs) - mc.extsb(r.SCRATCH.value, r.SCRATCH.value) - mc.cmpwi(0, r.SCRATCH.value, 0) + # the status of cr0! + card_marking_mask = descr.jit_wb_cards_set_singlebyte + mc.lbz(r.RCS2.value, r.RCS2.value, descr.jit_wb_if_flag_byteofs) + mc.andix(r.RCS2.value, r.RCS2.value, card_marking_mask & 0xFF) # - mc.addi(r.SP.value, r.SP.value, frame_size) - mc.blr() - # + + if not for_frame: + self._pop_all_regs_from_jitframe(mc, ignored_regs, withfloats) + mc.blr() + else: + XXXXXXX + if IS_X86_32: + mc.MOV_rs(edx.value, 4 * WORD) + if self.cpu.supports_floats: + mc.MOVSD_xs(xmm0.value, 2 * WORD) + mc.MOV_rs(eax.value, WORD) # restore + self._restore_exception(mc, exc0, exc1) + mc.MOV(exc0, RawEspLoc(WORD * 5, REF)) + mc.MOV(exc1, RawEspLoc(WORD * 6, INT)) + mc.LEA_rs(esp.value, 7 * WORD) + mc.RET() + + self.mc = old_mc rawstart = mc.materialize(self.cpu, []) - self.wb_slowpath[withcards + 2 * withfloats] = rawstart + if for_frame: + self.wb_slowpath[4] = rawstart + else: + self.wb_slowpath[withcards + 2 * withfloats] = rawstart def _build_propagate_exception_path(self): if not self.cpu.propagate_exception_descr: return - mc = PPCBuilder() - # the following call may be needed in the future: - # self._store_and_reset_exception() + self.mc = PPCBuilder() + # + # read and reset the current exception - mc.load_imm(r.RES, self.cpu.propagate_exception_descr) - self._gen_epilogue(mc) - self.propagate_exception_path = mc.materialize(self.cpu, []) + propagate_exception_descr = rffi.cast(lltype.Signed, + cast_instance_to_gcref(self.cpu.propagate_exception_descr)) + ofs3 = self.cpu.get_ofs_of_frame_field('jf_guard_exc') + ofs4 = self.cpu.get_ofs_of_frame_field('jf_descr') + + self._store_and_reset_exception(self.mc, r.r3) + self.mc.load_imm(r.r4, propagate_exception_descr) + self.mc.std(r.r3.value, r.SPP.value, ofs3) + self.mc.std(r.r4.value, r.SPP.value, ofs4) + # + self._call_footer() + rawstart = self.mc.materialize(self.cpu, []) + self.propagate_exception_path = rawstart + self.mc = None # The code generated here serves as an exit stub from # the executed machine code. @@ -617,28 +645,6 @@ return mc.materialize(self.cpu, [], self.cpu.gc_ll_descr.gcrootmap) - def _gen_epilogue(self, mc): - XXX - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap and gcrootmap.is_shadow_stack: - self.gen_footer_shadowstack(gcrootmap, mc) - - # save SPP back in r3 - mc.mr(r.r5.value, r.SPP.value) - self._restore_nonvolatiles(mc, r.r5) - # load old backchain into r4 - if IS_PPC_32: - ofs = WORD - else: - ofs = WORD * 2 - mc.load(r.r4.value, r.r5.value, self.OFFSET_SPP_TO_OLD_BACKCHAIN + ofs) - mc.mtlr(r.r4.value) # restore LR - # From SPP, we have a constant offset to the old backchain. We use the - # SPP to re-establish the old backchain because this exit stub is - # generated before we know how much space the entire frame will need. - mc.addi(r.SP.value, r.r5.value, self.OFFSET_SPP_TO_OLD_BACKCHAIN) # restore old SP - mc.blr() - def _save_managed_regs(self, mc): """ store managed registers in ENCODING AREA """ @@ -735,7 +741,7 @@ offset = self.mc.currpos() - patch_loc # pmc = OverwritingBuilder(self.mc, patch_loc, 1) - pmc.bc(4, 1, offset) # jump if SCRATCH <= r16, i. e. not(SCRATCH > r16) + pmc.ble(offset) # jump if SCRATCH <= r16, i. e. not(SCRATCH > r16) pmc.overwrite() def _call_footer(self): @@ -944,97 +950,11 @@ self.teardown() return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos) - DESCR_REF = 0x00 - DESCR_INT = 0x01 - DESCR_FLOAT = 0x02 - DESCR_SPECIAL = 0x03 - CODE_FROMSTACK = 128 - CODE_STOP = 0 | DESCR_SPECIAL - CODE_HOLE = 4 | DESCR_SPECIAL - CODE_INPUTARG = 8 | DESCR_SPECIAL - - def gen_descr_encoding(self, descr, failargs, locs): - assert self.mc is not None - buf = [] - for i in range(len(failargs)): - arg = failargs[i] - if arg is not None: - if arg.type == REF: - kind = self.DESCR_REF - elif arg.type == INT: - kind = self.DESCR_INT - elif arg.type == FLOAT: - kind = self.DESCR_FLOAT - else: - raise AssertionError("bogus kind") - loc = locs[i] - if loc.is_stack(): - pos = loc.position - if pos < 0: - buf.append(self.CODE_INPUTARG) - pos = ~pos - n = self.CODE_FROMSTACK // 4 + pos - else: - assert loc.is_reg() or loc.is_fp_reg() - n = loc.value - n = kind + 4 * n - while n > 0x7F: - buf.append((n & 0x7F) | 0x80) - n >>= 7 - else: - n = self.CODE_HOLE - buf.append(n) - buf.append(self.CODE_STOP) - - fdescr = self.cpu.get_fail_descr_number(descr) - - buf.append((fdescr >> 24) & 0xFF) - buf.append((fdescr >> 16) & 0xFF) - buf.append((fdescr >> 8) & 0xFF) - buf.append( fdescr & 0xFF) - - lenbuf = len(buf) - # XXX fix memory leaks - enc_arr = lltype.malloc(rffi.CArray(rffi.CHAR), lenbuf, - flavor='raw', track_allocation=False) - enc_ptr = rffi.cast(lltype.Signed, enc_arr) - for i, byte in enumerate(buf): - enc_arr[i] = chr(byte) - # assert that the fail_boxes lists are big enough - assert len(failargs) <= self.fail_boxes_int.SIZE - return enc_ptr - - def align(self, size): - while size % 8 != 0: - size += 1 - return size - def teardown(self): self.pending_guard_tokens = None self.mc = None self.current_clt = None - def compute_frame_depth(self, spilling_area, param_depth): - PARAMETER_AREA = param_depth * WORD - if IS_PPC_64: - PARAMETER_AREA += MAX_REG_PARAMS * WORD - SPILLING_AREA = spilling_area * WORD - - frame_depth = ( GPR_SAVE_AREA - + FPR_SAVE_AREA - + FLOAT_INT_CONVERSION - + FORCE_INDEX - + self.ENCODING_AREA - + SPILLING_AREA - + PARAMETER_AREA - + BACKCHAIN_SIZE * WORD) - - # align stack pointer - while frame_depth % (4 * WORD) != 0: - frame_depth += WORD - - return frame_depth - def _find_failure_recovery_bytecode(self, faildescr): return faildescr._failure_recovery_code_adr @@ -1207,7 +1127,8 @@ with scratch_reg(self.mc): offset = loc.value self.mc.load_imm(r.SCRATCH, value) - self.mc.store(r.SCRATCH.value, r.SPP.value, offset) + self.mc.lfdx(r.FP_SCRATCH.value, 0, r.SCRATCH.value) + self.mc.stfd(r.FP_SCRATCH.value, r.SPP.value, offset) return assert 0, "not supported location" elif prev_loc.is_fp_reg(): @@ -1258,13 +1179,13 @@ self.mc.lfd(loc.value, r.SP.value, index) else: self.mc.lfd(r.FP_SCRATCH.value, r.SP.value, index) - self.regalloc_mov(r.FP_SCRATCH.value, loc) + self.regalloc_mov(r.FP_SCRATCH, loc) else: if loc.is_core_reg(): self.mc.ld(loc.value, r.SP.value, index) else: self.mc.ld(r.SCRATCH.value, r.SP.value, index) - self.regalloc_mov(r.SCRATCH.value, loc) + self.regalloc_mov(r.SCRATCH, loc) def malloc_cond(self, nursery_free_adr, nursery_top_adr, size): assert size & (WORD-1) == 0 # must be correctly aligned @@ -1301,7 +1222,7 @@ offset = self.mc.currpos() - fast_jmp_pos pmc = OverwritingBuilder(self.mc, fast_jmp_pos, 1) - pmc.bc(4, 1, offset) # jump if LE (not GT) + pmc.ble(offset) # jump if LE (not GT) pmc.overwrite() with scratch_reg(self.mc): @@ -1318,8 +1239,10 @@ gcrootmap.write_callshape(mark, force_index) def propagate_memoryerror_if_r3_is_null(self): - return # XXXXXXXXX - self.mc.cmp_op(0, r.RES.value, 0, imm=True) + # if self.propagate_exception_path == 0 (tests), this may jump to 0 + # and segfaults. too bad. the alternative is to continue anyway + # with r3==0, but that will segfault too. + self.mc.cmp_op(0, r.r3.value, 0, imm=True) self.mc.b_cond_abs(self.propagate_exception_path, c.EQ) def write_new_force_index(self): diff --git a/rpython/jit/backend/ppc/regalloc.py b/rpython/jit/backend/ppc/regalloc.py --- a/rpython/jit/backend/ppc/regalloc.py +++ b/rpython/jit/backend/ppc/regalloc.py @@ -490,7 +490,7 @@ prepare_int_force_ge_zero = helper.prepare_unary_op - def prepare_math_sqrt(self, op): + def _prepare_math_sqrt(self, op): loc = self.ensure_reg(op.getarg(1)) self.free_op_vars() res = self.fprm.force_allocate_reg(op.result) @@ -839,8 +839,17 @@ return [base_loc, index_loc, value_loc, ofs_loc, imm_size, imm_size] - #prepare_copystrcontent = void - #prepare_copyunicodecontent = void + def prepare_copystrcontent(self, op): + src_ptr_loc = self.ensure_reg(op.getarg(0)) + dst_ptr_loc = self.ensure_reg(op.getarg(1)) + src_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(2)) + dst_ofs_loc = self.ensure_reg_or_any_imm(op.getarg(3)) + length_loc = self.ensure_reg_or_any_imm(op.getarg(4)) + self._spill_before_call(save_all_regs=False) + return [src_ptr_loc, dst_ptr_loc, + src_ofs_loc, dst_ofs_loc, length_loc] + + prepare_copyunicodecontent = prepare_copystrcontent def prepare_unicodelen(self, op): basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE, @@ -877,22 +886,21 @@ prepare_cast_ptr_to_int = prepare_same_as prepare_cast_int_to_ptr = prepare_same_as + def get_oopspecindex(self, op): + descr = op.getdescr() + assert descr is not None + effectinfo = descr.get_extra_info() + if effectinfo is not None: + return effectinfo.oopspecindex + return EffectInfo.OS_NONE + def prepare_call(self, op): - effectinfo = op.getdescr().get_extra_info() - if effectinfo is not None: - oopspecindex = effectinfo.oopspecindex - if oopspecindex == EffectInfo.OS_MATH_SQRT: - xxxxxxxxx - args = self.prepare_math_sqrt(op) - self.assembler.emit_math_sqrt(op, args, self) - return + oopspecindex = self.get_oopspecindex(op) + if oopspecindex == EffectInfo.OS_MATH_SQRT: + return self._prepare_math_sqrt(op) return self._prepare_call(op) - def _prepare_call(self, op, save_all_regs=False): - args = [] - args.append(None) - for i in range(op.numargs()): - args.append(self.loc(op.getarg(i))) + def _spill_before_call(self, save_all_regs=False): # spill variables that need to be saved around calls self.fprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -900,10 +908,16 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + + def _prepare_call(self, op, save_all_regs=False): + args = [] + args.append(None) + for i in range(op.numargs()): + args.append(self.loc(op.getarg(i))) + self._spill_before_call(save_all_regs) if op.result: resloc = self.after_call(op.result) args[0] = resloc - self.before_call_called = True return args def prepare_call_malloc_nursery(self, op): @@ -943,31 +957,16 @@ prepare_keepalive = void def prepare_cond_call_gc_wb(self, op): - assert op.result is None - # we force all arguments in a reg because it will be needed anyway by - # the following setfield_gc or setarrayitem_gc. It avoids loading it - # twice from the memory. - N = op.numargs() - args = op.getarglist() - arglocs = [self._ensure_value_is_boxed(op.getarg(i), args) - for i in range(N)] - card_marking = False - if op.getopnum() == rop.COND_CALL_GC_WB_ARRAY: - descr = op.getdescr() - if we_are_translated(): - cls = self.cpu.gc_ll_descr.has_write_barrier_class() - assert cls is not None and isinstance(descr, cls) - card_marking = descr.jit_wb_cards_set != 0 - if card_marking: # allocate scratch registers - tmp1 = self.get_scratch_reg(INT) - tmp2 = self.get_scratch_reg(INT) - tmp3 = self.get_scratch_reg(INT) - arglocs.append(tmp1) - arglocs.append(tmp2) - arglocs.append(tmp3) + arglocs = [self.ensure_reg(op.getarg(0))] return arglocs - prepare_cond_call_gc_wb_array = prepare_cond_call_gc_wb + def prepare_cond_call_gc_wb_array(self, op): + arglocs = [self.ensure_reg(op.getarg(0)), + self.ensure_reg_or_16bit_imm(op.getarg(1)), + None] + if arglocs[1].is_reg(): + arglocs[2] = self.get_scratch_reg(INT) + return arglocs def prepare_force_token(self, op): res_loc = self.force_allocate_reg(op.result) @@ -1028,21 +1027,11 @@ prepare_call_release_gil = prepare_call_may_force - def prepare_guard_call_assembler(self, op, guard_op): - descr = op.getdescr() - assert isinstance(descr, JitCellToken) - jd = descr.outermost_jitdriver_sd - assert jd is not None - vable_index = jd.index_of_virtualizable - if vable_index >= 0: - self._sync_var(op.getarg(vable_index)) - vable = self.frame_manager.loc(op.getarg(vable_index)) - else: - vable = imm(0) - # make sure the call result location is free - tmploc = self.get_scratch_reg(INT, selected_reg=r.RES) - self.possibly_free_vars(guard_op.getfailargs()) - return [vable, tmploc] + self._prepare_call(op, save_all_regs=True) + def prepare_call_assembler(self, op): + locs = self.locs_for_call_assembler(op) + self._spill_before_call(save_all_regs=True) + resloc = self.after_call(op.result) + return [resloc] + locs def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr @@ -1060,6 +1049,11 @@ self.force_spill_var(op.getarg(0)) return [] + def prepare_guard_not_forced_2(self, op): + self.rm.before_call(op.getfailargs(), save_all_regs=True) + arglocs = self._prepare_guard(op) + return arglocs + def prepare_zero_ptr_field(self, op): base_loc = self.ensure_reg(op.getarg(0)) ofs_loc = self.ensure_reg_or_16bit_imm(op.getarg(1)) diff --git a/rpython/jit/backend/ppc/runner.py b/rpython/jit/backend/ppc/runner.py --- a/rpython/jit/backend/ppc/runner.py +++ b/rpython/jit/backend/ppc/runner.py @@ -2,7 +2,6 @@ from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.llinterp import LLInterpreter from rpython.rlib import rgc -#from rpython.jit.backend.ppc.arch import FORCE_INDEX_OFS from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU from rpython.jit.backend.ppc.ppc_assembler import AssemblerPPC from rpython.jit.backend.ppc.arch import WORD @@ -33,11 +32,6 @@ def __init__(self, rtyper, stats, opts=None, translate_support_code=False, gcdescr=None): - if gcdescr is not None: - gcdescr.force_index_ofs = FORCE_INDEX_OFS - # XXX for now the ppc backend does not support the gcremovetypeptr - # translation option - # assert gcdescr.config.translation.gcremovetypeptr is False AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code, gcdescr) @@ -80,8 +74,7 @@ for jmp, tgt in looptoken.compiled_loop_token.invalidate_positions: mc = PPCBuilder() - mc.b_offset(tgt) - mc.prepare_insts_blocks() + mc.b_offset(tgt) # a single instruction mc.copy_to_raw_memory(jmp) # positions invalidated looptoken.compiled_loop_token.invalidate_positions = [] diff --git a/rpython/jit/backend/ppc/symbol_lookup.py b/rpython/jit/backend/ppc/symbol_lookup.py deleted file mode 100644 --- a/rpython/jit/backend/ppc/symbol_lookup.py +++ /dev/null @@ -1,15 +0,0 @@ - -def lookup(sym): - global lookup - import py - - _ppcgen = py.magic.autopath().dirpath().join('_ppcgen.c')._getpymodule() - - try: - from _ppcgen import NSLookupAndBindSymbol - - def lookup(sym): - return NSLookupAndBindSymbol('_' + sym) - except ImportError: - from _ppcgen import dlsym as lookup - return lookup(sym) diff --git a/rpython/jit/backend/ppc/test/test_ppc.py b/rpython/jit/backend/ppc/test/test_ppc.py --- a/rpython/jit/backend/ppc/test/test_ppc.py +++ b/rpython/jit/backend/ppc/test/test_ppc.py @@ -2,7 +2,6 @@ import random, sys, os from rpython.jit.backend.ppc.codebuilder import BasicPPCAssembler, PPCBuilder -from rpython.jit.backend.ppc.symbol_lookup import lookup from rpython.jit.backend.ppc.regname import * from rpython.jit.backend.ppc.register import * from rpython.jit.backend.ppc import form diff --git a/rpython/jit/backend/ppc/test/test_runner.py b/rpython/jit/backend/ppc/test/test_runner.py --- a/rpython/jit/backend/ppc/test/test_runner.py +++ b/rpython/jit/backend/ppc/test/test_runner.py @@ -23,16 +23,22 @@ # ====> ../../test/runner_test.py if IS_PPC_32: - add_loop_instructions = ["mr", "add", "cmpwi", "beq", "b"] + add_loop_instructions = ["ld", "add", "cmpwi", "beq", "b"] else: - add_loop_instructions = ["mr", "add", "cmpdi", "beq", "b"] - bridge_loop_instructions_short = ["lis", "ori", "mtctr", "bctr"] - bridge_loop_instructions_long = ["lis", "ori", "rldicr", "oris", "ori", - "mtctr", "bctr"] - - def setup_method(self, meth): - self.cpu = PPC_CPU(rtyper=None, stats=FakeStats()) - self.cpu.setup_once() + add_loop_instructions = ["ld", "add", "cmpdi", "beq", "b"] + bridge_loop_instructions = [ + "ld", "cmpdi", "bge+", + "li", "lis", "ori", "mtctr", "bctrl", + "lis", "ori", "mtctr", "bctr"] + bridge_loop_instructions_alternative = [ + "ld", "cmpdi", "bge+", + "li", "li", "rldicr", "oris", "ori", "mtctr", "bctrl", + "li", "rldicr", "oris", "ori", "mtctr", "bctr"] + + def get_cpu(self): + cpu = PPC_CPU(rtyper=None, stats=FakeStats()) + cpu.setup_once() + return cpu def test_compile_loop_many_int_args(self): for numargs in range(2, 16): diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -1113,12 +1113,12 @@ r_box = self.alloc_string("!???????!") if r_box_is_const: r_box = r_box.constbox() - self.execute_operation(rop.COPYSTRCONTENT, - [s_box, r_box, - srcstart_box, - dststart_box, - length_box], 'void') - assert self.look_string(r_box) == "!??cdef?!" + self.execute_operation(rop.COPYSTRCONTENT, + [s_box, r_box, + srcstart_box, + dststart_box, + length_box], 'void') + assert self.look_string(r_box) == "!??cdef?!" def test_copyunicodecontent(self): s_box = self.alloc_unicode(u"abcdef") @@ -1130,12 +1130,12 @@ r_box = self.alloc_unicode(u"!???????!") if r_box_is_const: r_box = r_box.constbox() - self.execute_operation(rop.COPYUNICODECONTENT, - [s_box, r_box, - srcstart_box, - dststart_box, - length_box], 'void') - assert self.look_unicode(r_box) == u"!??cdef?!" + self.execute_operation(rop.COPYUNICODECONTENT, + [s_box, r_box, + srcstart_box, + dststart_box, + length_box], 'void') + assert self.look_unicode(r_box) == u"!??cdef?!" def test_do_unicode_basic(self): u = self.cpu.bh_newunicode(5) @@ -2178,7 +2178,7 @@ funcbox = self.get_funcbox(self.cpu, func_ptr) class WriteBarrierDescr(AbstractDescr): jit_wb_if_flag = 4096 - jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 def get_write_barrier_fn(self, cpu): return funcbox.getint() @@ -2212,7 +2212,7 @@ funcbox = self.get_funcbox(self.cpu, func_ptr) class WriteBarrierDescr(AbstractDescr): jit_wb_if_flag = 4096 - jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 jit_wb_cards_set = 0 # <= without card marking def get_write_barrier_fn(self, cpu): @@ -2259,10 +2259,10 @@ funcbox = self.get_funcbox(self.cpu, func_ptr) class WriteBarrierDescr(AbstractDescr): jit_wb_if_flag = 4096 - jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10') + jit_wb_if_flag_byteofs = struct.pack("l", 4096).index('\x10') jit_wb_if_flag_singlebyte = 0x10 jit_wb_cards_set = 32768 - jit_wb_cards_set_byteofs = struct.pack("i", 32768).index('\x80') + jit_wb_cards_set_byteofs = struct.pack("l", 32768).index('\x80') jit_wb_cards_set_singlebyte = -0x80 jit_wb_card_page_shift = 7 def get_write_barrier_from_array_fn(self, cpu): @@ -3674,6 +3674,7 @@ assert not called def test_assembler_call_propagate_exc(self): + # WARNING: this test depends on test_memoryerror first passing if not isinstance(self.cpu, AbstractLLCPU): py.test.skip("llgraph can't fake exceptions well enough, give up") @@ -4985,3 +4986,35 @@ assert a[i].a == a[i].b == val else: assert a[i] == rffi.cast(OF, val) + + def test_jump_float_constant(self): + f0 = BoxFloat() + f1 = BoxFloat() + i2 = BoxInt() + f3 = BoxFloat() + i4 = BoxInt() + looptoken = JitCellToken() + targettoken = TargetToken() + operations = [ + ResOperation(rop.LABEL, [f0, f1], None, descr=targettoken), + ResOperation(rop.CAST_FLOAT_TO_INT, [f1], i2), + ResOperation(rop.GUARD_VALUE, [i2, ConstInt(123456)], None, + descr=BasicFailDescr(6)), + ResOperation(rop.FLOAT_ADD, [f0, ConstFloat(-0.5)], f3), + ResOperation(rop.FLOAT_GT, [f3, ConstFloat(9.12)], i4), + ResOperation(rop.GUARD_TRUE, [i4], None, descr=BasicFailDescr(2)), + ResOperation(rop.JUMP, [f3, ConstFloat(123456.78912)], None, + descr=targettoken), + ] + inputargs = [f0, f1] + operations[2].setfailargs([]) + operations[-2].setfailargs([f1, f3]) + + self.cpu.compile_loop(inputargs, operations, looptoken) + deadframe = self.cpu.execute_token(looptoken, 12.25, 123456.01) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 2 + res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 0)) + assert res == 123456.78912 + res = longlong.getrealfloat(self.cpu.get_float_value(deadframe, 1)) + assert res == 8.75 diff --git a/rpython/jit/backend/tool/viewcode.py b/rpython/jit/backend/tool/viewcode.py --- a/rpython/jit/backend/tool/viewcode.py +++ b/rpython/jit/backend/tool/viewcode.py @@ -49,10 +49,12 @@ 'arm': 'arm', 'arm_32': 'arm', 'ppc' : 'powerpc:common64', + 'ppc-64' : 'powerpc:common64', } machine_endianness = { # default value: 'little' 'ppc' : sys.byteorder, # i.e. same as the running machine... + 'ppc-64' : sys.byteorder, # i.e. same as the running machine... } cmd = find_objdump() objdump = ('%(command)s -b binary -m %(machine)s ' From noreply at buildbot.pypy.org Fri Sep 18 08:51:05 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 08:51:05 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit fix Message-ID: <20150918065105.23B6D1C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79682:7438411d56f7 Date: 2015-09-18 08:51 +0200 http://bitbucket.org/pypy/pypy/changeset/7438411d56f7/ Log: 32-bit fix diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -415,8 +415,10 @@ return self._resfloat getvalue = getfloatstorage - getfloat = getfloatstorage - + + def getfloat(self): + return longlong.getrealfloat(self.getfloatstorage()) + def setfloatstorage(self, floatval): assert lltype.typeOf(floatval) is longlong.FLOATSTORAGE self._resfloat = floatval From noreply at buildbot.pypy.org Fri Sep 18 11:45:28 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 18 Sep 2015 11:45:28 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: beating the integraiton tests, roughly half work already Message-ID: <20150918094528.493091C076F@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79683:5190c354f531 Date: 2015-09-18 11:45 +0200 http://bitbucket.org/pypy/pypy/changeset/5190c354f531/ Log: beating the integraiton tests, roughly half work already 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 @@ -32,9 +32,9 @@ def build_opt_chain(metainterp_sd, enable_opts): optimizations = [] unroll = 'unroll' in enable_opts # 'enable_opts' is normally a dict - #if (metainterp_sd.cpu is not None and - # not metainterp_sd.cpu.supports_guard_gc_type): - # unroll = False + if (metainterp_sd.cpu is not None and + not metainterp_sd.cpu.supports_guard_gc_type): + unroll = False for name, opt in unroll_all_opts: if name in enable_opts: if opt is not None: diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -71,7 +71,11 @@ if exclude_last: count -= 1 while i < count: - op = self.path[i].getoperation() + node = self.path[i] + if node.is_imaginary(): + i += 1 + continue + op = node.getoperation() if op.is_guard(): descr = op.getdescr() if not descr: @@ -189,9 +193,6 @@ isinstance(descr, compile.CompileLoopVersionDescr) return False - # TODO def is_guard_early_exit(self): - # return self.op.getopnum() == rop.GUARD_EARLY_EXIT - def loads_from_complex_object(self): return rop._ALWAYS_PURE_LAST <= self.op.getopnum() < rop._MALLOC_FIRST @@ -1057,33 +1058,27 @@ return self.constant - other.constant def emit_operations(self, opt, result_box=None): - box = self.var + var = self.var if self.is_identity(): - return box + return var last_op = None if self.coefficient_mul != 1: - box_result = box.clonebox() - last_op = ResOperation(rop.INT_MUL, [box, ConstInt(self.coefficient_mul)], box_result) - opt.emit_operation(last_op) - box = box_result + args = [var, ConstInt(self.coefficient_mul)] + var = ResOperation(rop.INT_MUL, args) + opt.emit_operation(var) if self.coefficient_div != 1: - box_result = box.clonebox() - last_op = ResOperation(rop.INT_FLOORDIV, [box, ConstInt(self.coefficient_div)], box_result) - opt.emit_operation(last_op) - box = box_result + args = [var, ConstInt(self.coefficient_div)] + var = ResOperation(rop.INT_FLOORDIV, args) + opt.emit_operation(var) if self.constant > 0: - box_result = box.clonebox() - last_op = ResOperation(rop.INT_ADD, [box, ConstInt(self.constant)], box_result) - opt.emit_operation(last_op) - box = box_result + args = [var, ConstInt(self.constant)] + vec = ResOperation(rop.INT_ADD, args) + opt.emit_operation(vec) if self.constant < 0: - box_result = box.clonebox() - last_op = ResOperation(rop.INT_SUB, [box, ConstInt(self.constant)], box_result) - opt.emit_operation(last_op) - box = box_result - if result_box is not None: - last_op.result = box = result_box - return box + args = [var, ConstInt(self.constant)] + var = ResOperation(rop.INT_SUB, args) + opt.emit_operation(var) + return var def compare(self, other): """ Returns if the two are compareable as a first result diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -133,15 +133,13 @@ def emit_operations(self, opt): # create trace instructions for the index - box_lhs = self.emit_varops(opt, self.lhs, self.cmp_op.getarg(0)) - box_rhs = self.emit_varops(opt, self.rhs, self.cmp_op.getarg(1)) - box_result = self.cmp_op.result.clonebox() + lhs = self.emit_varops(opt, self.lhs, self.cmp_op.getarg(0)) + rhs = self.emit_varops(opt, self.rhs, self.cmp_op.getarg(1)) opnum = self.cmp_op.getopnum() - cmp_op = ResOperation(opnum, [box_lhs, box_rhs], box_result) + cmp_op = ResOperation(opnum, [lhs, rhs]) opt.emit_operation(cmp_op) # emit that actual guard - guard = self.op.clone() - guard.setarg(0, box_result) + guard = ResOperation(self.op.getopnum(), [cmp_op], self.op.getdescr()) opt.emit_operation(guard) self.setindex(opt.operation_position()-1) self.setoperation(guard) @@ -179,13 +177,12 @@ class GuardStrengthenOpt(object): """ Note that this optimization is only used in the vector optimizer (yet) """ - def __init__(self, index_vars, has_two_labels): + def __init__(self, index_vars): self.index_vars = index_vars self._newoperations = [] self.strength_reduced = 0 # how many guards could be removed? self.strongest_guards = {} self.guards = {} - self.has_two_labels = has_two_labels def collect_guard_information(self, loop): operations = loop.operations @@ -251,11 +248,11 @@ else: self.emit_operation(op) continue - if op.result: - index_var = self.index_vars.get(op.result, None) + if not op.returns_void(): + index_var = self.index_vars.get(op, None) if index_var: if not index_var.is_identity(): - index_var.emit_operations(self, op.result) + index_var.emit_operations(self, op) continue self.emit_operation(op) # diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -124,7 +124,6 @@ """ Emit all the operations into the oplist parameter. Initiates the scheduling. """ assert isinstance(state, SchedulerState) - import pdb; pdb.set_trace() while state.has_more(): node = self.next(state) if node: diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -51,8 +51,10 @@ else: label = loop.operations[0] label.setdescr(TargetToken(token)) - loop = VectorLoop(label, loop.operations[0:-1], loop.operations[-1]) + jump = loop.operations[-1] + loop = VectorLoop(label, loop.operations[0:-1], jump) loop.jump.setdescr(token) + # TODO for op in loop.operations: if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: op.setdescr(ResumeAtLoopHeaderDescr()) @@ -184,10 +186,6 @@ assert not m1.is_adjacent_to(m2) assert not m2.is_adjacent_to(m1) - def getmemref(self, idx): - node = self.last_graph.getnode(idx) - return self.last_graph.memory_refs[node] - class BaseTestDependencyGraph(DependencyBaseTest): def test_index_var_basic(self): @@ -264,9 +262,9 @@ jump() # 4: """ graph = self.assert_dependencies(ops, full_check=True) - self.assert_dependent(1,2) - self.assert_dependent(2,3) - self.assert_dependent(1,3) + self.assert_dependent(graph, 1,2) + self.assert_dependent(graph, 2,3) + self.assert_dependent(graph, 1,3) def test_def_use_jump_use_def(self): ops = """ @@ -417,7 +415,7 @@ jump(p0, i1, i2) # 3: """ self.assert_dependencies(ops, full_check=True) - self.assert_dependent(1,2) + self.assert_dependent(graph, 1,2) def test_setarrayitem_dont_depend_with_memref_info(self): ops=""" @@ -457,7 +455,7 @@ jump(i24, i19, i21, i3, i4, i5, i22, i7) # 21: """ self.assert_dependencies(ops, full_check=False) - self.assert_dependent(2,12) + self.assert_dependent(graph, 2,12) def test_getfield(self): trace = """ diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -11,20 +11,31 @@ import rpython.jit.metainterp.optimizeopt.optimizer as optimizeopt import rpython.jit.metainterp.optimizeopt.virtualize as virtualize from rpython.jit.metainterp.optimizeopt.dependency import DependencyGraph -from rpython.jit.metainterp.optimizeopt.vector import (VectorizingOptimizer, MemoryRef, - isomorphic, Pair, NotAVectorizeableLoop, NotAProfitableLoop, GuardStrengthenOpt, - CostModel, VectorLoop) -from rpython.jit.metainterp.optimizeopt.schedule import (Scheduler, SchedulerState) +from rpython.jit.metainterp.optimizeopt.vector import (VectorizingOptimizer, + MemoryRef, isomorphic, Pair, NotAVectorizeableLoop, VectorLoop, + NotAProfitableLoop, GuardStrengthenOpt, CostModel, X86_CostModel) +from rpython.jit.metainterp.optimizeopt.schedule import (Scheduler, + SchedulerState, VecScheduleState) from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp import compile from rpython.jit.metainterp.resoperation import rop, ResOperation +from rpython.jit.metainterp.optimizeopt.version import LoopVersionInfo class FakeJitDriverStaticData(object): vec=True +class FakeLoopInfo(LoopVersionInfo): + def __init__(self, loop): + self.target_token = loop.label.getdescr() + self.label_op = loop.label + self.insert_index = -1 + self.versions = [] + self.leads_to = {} + self.descrs = [] + class FakeCostModel(CostModel): - def __init__(self): - CostModel.__init__(self, 0, 16) + def __init__(self, cpu): + CostModel.__init__(self, cpu, 16) def record_cast_int(self): pass def record_pack_savings(self, pack, times): pass def record_vector_pack(self, box, index, count): pass @@ -34,6 +45,19 @@ def profitable(self): return True +def index_of_first(opnum, operations, pass_by=0): + for i,op in enumerate(operations): + if op.getopnum() == opnum: + if pass_by == 0: + return i + else: + pass_by -= 1 + return -1 + +def find_first_index(loop, opnum, pass_by=0): + """ return the first index of the operation having the same opnum or -1 """ + return index_of_first(opnum, loop.operations, pass_by) + ARCH_VEC_REG_SIZE = 16 class VecTestHelper(DependencyBaseTest): @@ -43,7 +67,11 @@ jitdriver_sd = FakeJitDriverStaticData() def assert_vectorize(self, loop, expected_loop, call_pure_results=None): - self._do_optimize_loop(loop) + jump = ResOperation(rop.LABEL, loop.jump.getarglist(), loop.jump.getdescr()) + compile_data = compile.LoopCompileData(loop.label, jump, loop.operations) + state = self._do_optimize_loop(compile_data) + loop.label = state[0].label_op + loop.opererations = state[1] self.assert_equal(loop, expected_loop) def vectoroptimizer(self, loop): @@ -56,13 +84,11 @@ def earlyexit(self, loop): opt = self.vectoroptimizer(loop) graph = opt.analyse_index_calculations(loop) - graph.view() state = SchedulerState(graph) opt.schedule(state) return graph.loop def vectoroptimizer_unrolled(self, loop, unroll_factor = -1): - loop.snapshot() opt = self.vectoroptimizer(loop) opt.linear_find_smallest_type(loop) if unroll_factor == -1 and opt.smallest_type_bytes == 0: @@ -71,76 +97,84 @@ unroll_factor = opt.get_unroll_count(ARCH_VEC_REG_SIZE) print "" print "unroll factor: ", unroll_factor, opt.smallest_type_bytes - if opt.loop.find_first_index(rop.GUARD_EARLY_EXIT) == -1: - idx = loop.find_first_index(rop.LABEL) - guard = ResOperation(rop.GUARD_EARLY_EXIT, [], None) - guard.setfailargs([]) - guard.setdescr(compile.ResumeAtLoopHeaderDescr()) - loop.operations.insert(idx+1, guard) - self.show_dot_graph(DependencyGraph(opt.loop), "original_" + self.test_name) - graph = opt.analyse_index_calculations() + # TODO if opt.loop.find_first_index(rop.GUARD_EARLY_EXIT) == -1: + # idx = loop.find_first_index(rop.LABEL) + # guard = ResOperation(rop.GUARD_EARLY_EXIT, [], None) + # guard.setfailargs([]) + # guard.setdescr(compile.ResumeAtLoopHeaderDescr()) + # loop.operations.insert(idx+1, guard) + self.show_dot_graph(DependencyGraph(loop), "original_" + self.test_name) + graph = opt.analyse_index_calculations(loop) if graph is not None: - cycle = opt.dependency_graph.cycles() + cycle = graph.cycles() if cycle is not None: print "CYCLE found %s" % cycle - self.show_dot_graph(opt.dependency_graph, "early_exit_" + self.test_name) + self.show_dot_graph(graph, "early_exit_" + self.test_name) assert cycle is None - loop.operations = opt.schedule(False) + state = SchedulerState(graph) + opt.schedule(state) opt.unroll_loop_iterations(loop, unroll_factor) - opt.loop.operations = opt.get_newoperations() - self.debug_print_operations(opt.loop) - opt.clear_newoperations() + self.debug_print_operations(loop) graph = DependencyGraph(loop) - self.last_graph = graph - self.show_dot_graph(self.last_graph, self.test_name) + self.last_graph = graph # legacy for test_dependency + self.show_dot_graph(graph, self.test_name) + def gmr(i): + return graph.memory_refs[graph.nodes[i]] + graph.getmemref = gmr return opt, graph def init_packset(self, loop, unroll_factor = -1): opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.find_adjacent_memory_refs(graph) - return opt + return opt, graph def extend_packset(self, loop, unroll_factor = -1): opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.find_adjacent_memory_refs(graph) opt.extend_packset() - return opt + return opt, graph def combine_packset(self, loop, unroll_factor = -1): opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() - return opt + return opt, graph def schedule(self, loop, unroll_factor = -1, with_guard_opt=False): + info = FakeLoopInfo(loop) + info.snapshot(loop.operations + [loop.jump], loop.label) opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) - opt.costmodel = FakeCostModel() opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() - opt.schedule(graph, True) + costmodel = FakeCostModel(self.cpu) + state = VecScheduleState(graph, opt.packset, self.cpu, costmodel) + opt.schedule(state) if with_guard_opt: - gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) - gso.propagate_all_forward(opt.loop) + gso = GuardStrengthenOpt(graph.index_vars) + gso.propagate_all_forward(info, loop) return opt def vectorize(self, loop, unroll_factor = -1): - opt = self.vectoroptimizer_unrolled(loop, unroll_factor) - opt.find_adjacent_memory_refs() + info = FakeLoopInfo(loop) + info.snapshot(loop.operations + [loop.jump], loop.label) + opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) + opt.find_adjacent_memory_refs(graph) opt.extend_packset() opt.combine_packset() - opt.costmodel.reset_savings() - opt.schedule(True) - if not opt.costmodel.profitable(): + costmodel = X86_CostModel(self.cpu, 0) + state = VecScheduleState(graph, opt.packset, self.cpu, costmodel) + opt.schedule(state) + if not costmodel.profitable(): raise NotAProfitableLoop() - gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) - gso.propagate_all_forward(opt.loop) + gso = GuardStrengthenOpt(graph.index_vars) + gso.propagate_all_forward(info, loop) return opt def assert_unroll_loop_equals(self, loop, expected_loop, \ unroll_factor = -1): - vectoroptimizer = self.vectoroptimizer_unrolled(loop, unroll_factor) + self.vectoroptimizer_unrolled(loop, unroll_factor) self.assert_equal(loop, expected_loop) def assert_pack(self, pack, indices): @@ -171,23 +205,24 @@ def assert_packset_not_contains_pair(self, packset, x, y): for pack in packset.packs: - if pack.left.opidx == x and \ - pack.right.opidx == y: + if pack.leftmost(node=True).opidx == x and \ + pack.rightmost(node=True).opidx == y: pytest.fail("must not find packset with indices {x},{y}" \ .format(x=x,y=y)) def assert_packset_contains_pair(self, packset, x, y): for pack in packset.packs: if isinstance(pack, Pair): - if pack.left.opidx == x and \ - pack.right.opidx == y: + if pack.leftmost(node=True).opidx == x and \ + pack.rightmost(node=True).opidx == y: break else: pytest.fail("can't find a pack set for indices {x},{y}" \ .format(x=x,y=y)) - def assert_has_memory_ref_at(self, idx): - node = self.last_graph.nodes[idx] - assert node in self.last_graph.memory_refs, \ + def assert_has_memory_ref_at(self, graph, idx): + idx -= 1 # label is not in the nodes + node = graph.nodes[idx] + assert node in graph.memory_refs, \ "operation %s at pos %d has no memory ref!" % \ (node.getoperation(), node.getindex()) @@ -248,7 +283,7 @@ """ it currently rejects pointer arrays """ ops = """ [p0,i0] - raw_load_r(p0,i0,descr=arraydescr2) + getarrayitem_gc_r(p0,i0,descr=arraydescr2) jump(p0,i0) """ self.assert_vectorize(self.parse_loop(ops), self.parse_loop(ops)) @@ -257,9 +292,9 @@ """ it currently rejects pointer arrays """ ops = """ [p0,i0] - i2 = getarrayitem_gc(p0,i0,descr=floatarraydescr) + i2 = getarrayitem_gc_i(p0,i0,descr=arraydescr) i1 = int_add(i0,1) - i3 = getarrayitem_gc(p0,i1,descr=floatarraydescr) + i3 = getarrayitem_gc_i(p0,i1,descr=arraydescr) i4 = int_add(i1,1) jump(p0,i4) """ @@ -267,11 +302,12 @@ [p0,i0] i1 = int_add(i0,1) i2 = int_add(i0,2) - i3 = vec_getarrayitem_gc(p0,i0,2,descr=floatarraydescr) + v3[2xi64] = vec_getarrayitem_gc_i(p0,i0,descr=arraydescr) jump(p0,i2) """ - vopt = self.vectorize(self.parse_loop(ops),0) - self.assert_equal(vopt.loop, self.parse_loop(opt)) + loop = self.parse_loop(ops) + vopt = self.vectorize(loop,0) + self.assert_equal(loop, self.parse_loop(opt)) def test_vect_unroll_char(self): """ a 16 byte vector register can hold 16 bytes thus @@ -306,14 +342,14 @@ [p0,p1,p2,i0] i4 = int_add(i0, 1) i5 = int_le(i4, 10) - guard_true(i5) [] + guard_true(i5) [p0,p1,p2,i0] i1 = raw_load_i(p1, i0, descr=floatarraydescr) i2 = raw_load_i(p2, i0, descr=floatarraydescr) i3 = int_add(i1,i2) raw_store(p0, i0, i3, descr=floatarraydescr) i9 = int_add(i4, 1) i10 = int_le(i9, 10) - guard_true(i10) [] + guard_true(i10) [p0,p1,p2,i4] i6 = raw_load_i(p1, i4, descr=floatarraydescr) i7 = raw_load_i(p2, i4, descr=floatarraydescr) i8 = int_add(i6,i7) @@ -338,9 +374,9 @@ raw_load_i(p0,i0,descr=arraydescr) jump(p0,i0) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - assert len(vopt.dependency_graph.memory_refs) == 1 - self.assert_has_memory_ref_at(1) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + assert len(graph.memory_refs) == 1 + self.assert_has_memory_ref_at(graph, 1) def test_array_operation_indices_unrolled_1(self): ops = """ @@ -348,10 +384,10 @@ raw_load_i(p0,i0,descr=chararraydescr) jump(p0,i0) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) - assert len(vopt.dependency_graph.memory_refs) == 2 - self.assert_has_memory_ref_at(1) - self.assert_has_memory_ref_at(2) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) + assert len(graph.memory_refs) == 2 + self.assert_has_memory_ref_at(graph, 1) + self.assert_has_memory_ref_at(graph, 2) def test_array_operation_indices_unrolled_2(self): ops = """ @@ -361,20 +397,20 @@ jump(p0,i3,i4) """ loop = self.parse_loop(ops) - vopt = self.vectoroptimizer_unrolled(loop,0) - assert len(vopt.dependency_graph.memory_refs) == 2 - self.assert_has_memory_ref_at(1) - self.assert_has_memory_ref_at(2) + vopt, graph = self.vectoroptimizer_unrolled(loop,0) + assert len(graph.memory_refs) == 2 + self.assert_has_memory_ref_at(graph, 1) + self.assert_has_memory_ref_at(graph, 2) # - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) - assert len(vopt.dependency_graph.memory_refs) == 4 + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),1) + assert len(graph.memory_refs) == 4 for i in [1,2,3,4]: - self.assert_has_memory_ref_at(i) + self.assert_has_memory_ref_at(graph, i) # - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),3) - assert len(vopt.dependency_graph.memory_refs) == 8 + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),3) + assert len(graph.memory_refs) == 8 for i in [1,2,3,4,5,6,7,8]: - self.assert_has_memory_ref_at(i) + self.assert_has_memory_ref_at(graph, i) def test_array_memory_ref_adjacent_1(self): ops = """ @@ -384,12 +420,12 @@ jump(p0,i1) """ loop = self.parse_loop(ops) - vopt = self.vectoroptimizer_unrolled(loop,1) - vopt.find_adjacent_memory_refs() - assert len(vopt.dependency_graph.memory_refs) == 2 + vopt, graph = self.vectoroptimizer_unrolled(loop,1) + vopt.find_adjacent_memory_refs(graph) + assert len(graph.memory_refs) == 2 - mref1 = self.getmemref(loop.find_first_index(rop.RAW_LOAD)) - mref3 = self.getmemref(loop.find_first_index(rop.RAW_LOAD,1)) + mref1 = graph.getmemref(find_first_index(loop, rop.RAW_LOAD_I)) + mref3 = graph.getmemref(find_first_index(loop, rop.RAW_LOAD_I,1)) assert isinstance(mref1, MemoryRef) assert isinstance(mref3, MemoryRef) @@ -402,9 +438,9 @@ i3 = raw_load_i(p0,i0,descr=chararraydescr) jump(p0,i0) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(1) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(0) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 1 assert mref1.index_var.constant == 0 @@ -416,9 +452,9 @@ i3 = raw_load_i(p0,i1,descr=chararraydescr) jump(p0,i1) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(2) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(1) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 1 assert mref1.index_var.constant == 1 @@ -430,9 +466,9 @@ i3 = raw_load_i(p0,i1,descr=chararraydescr) jump(p0,i1) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(2) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(1) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 1 assert mref1.index_var.constant == -1 @@ -445,9 +481,9 @@ i3 = raw_load_i(p0,i2,descr=chararraydescr) jump(p0,i1) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(3) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(2) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 3 assert mref1.index_var.constant == 3 @@ -462,9 +498,9 @@ i5 = raw_load_i(p0,i4,descr=chararraydescr) jump(p0,i4) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(5) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(4) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 18 assert mref1.index_var.constant == 48 @@ -480,9 +516,9 @@ i7 = raw_load_i(p0,i6,descr=chararraydescr) jump(p0,i6) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(7) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(6) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 1026 assert mref1.index_var.coefficient_div == 1 @@ -498,9 +534,9 @@ i5 = raw_load_i(p0,i4,descr=chararraydescr) jump(p0,i4) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref1 = self.getmemref(5) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref1 = graph.getmemref(4) assert isinstance(mref1, MemoryRef) assert mref1.index_var.coefficient_mul == 6 assert mref1.index_var.coefficient_div == 1 @@ -516,16 +552,16 @@ jump(p0,i1,i6) """ loop = self.parse_loop(ops) - vopt = self.vectoroptimizer_unrolled(loop,1) - vopt.find_adjacent_memory_refs() + vopt, graph = self.vectoroptimizer_unrolled(loop,1) + vopt.find_adjacent_memory_refs(graph) - f = lambda x: loop.find_first_index(rop.RAW_LOAD, x) + f = lambda x: find_first_index(loop, rop.RAW_LOAD_I, x) indices = [f(0),f(1),f(2),f(3)] for i in indices: - self.assert_has_memory_ref_at(i) - assert len(vopt.dependency_graph.memory_refs) == 4 + self.assert_has_memory_ref_at(graph, i+1) + assert len(graph.memory_refs) == 4 - mref1, mref3, mref5, mref7 = [self.getmemref(i) for i in indices] + mref1, mref3, mref5, mref7 = [graph.getmemref(i) for i in indices] assert isinstance(mref1, MemoryRef) assert isinstance(mref3, MemoryRef) assert isinstance(mref5, MemoryRef) @@ -545,9 +581,9 @@ i3 = raw_load_i(p0,i2,descr=chararraydescr) jump(p0,i2) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref = self.getmemref(3) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref = graph.getmemref(2) assert mref.index_var.coefficient_div == 16 ops = """ [p0,i0] @@ -556,9 +592,9 @@ i3 = raw_load_i(p0,i2,descr=chararraydescr) jump(p0,i2) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref = self.getmemref(3) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref = graph.getmemref(2) assert mref.index_var.coefficient_div == 2 assert mref.index_var.constant == 4 ops = """ @@ -571,10 +607,10 @@ i6 = raw_load_i(p0,i5,descr=chararraydescr) jump(p0,i2) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref = self.getmemref(5) - mref2 = self.getmemref(6) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref = graph.getmemref(2) + mref2 = graph.getmemref(5) self.assert_memory_ref_not_adjacent(mref, mref2) assert mref != mref2 @@ -591,10 +627,10 @@ i7 = raw_load_i(p0,i6,descr=chararraydescr) jump(p0,i2) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref = self.getmemref(6) - mref2 = self.getmemref(7) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref = graph.getmemref(2) + mref2 = graph.getmemref(6) self.assert_memory_ref_not_adjacent(mref, mref2) assert mref == mref2 @@ -611,10 +647,10 @@ i7 = raw_load_i(p0,i6,descr=chararraydescr) jump(p0,i2) """ - vopt = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) - vopt.find_adjacent_memory_refs() - mref = self.getmemref(6) - mref2 = self.getmemref(7) + vopt, graph = self.vectoroptimizer_unrolled(self.parse_loop(ops),0) + vopt.find_adjacent_memory_refs(graph) + mref = graph.getmemref(2) + mref2 = graph.getmemref(6) self.assert_memory_ref_not_adjacent(mref, mref2) assert mref != mref2 @@ -622,17 +658,17 @@ def test_packset_init_simple(self): ops = """ [p0,i0] - i3 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i3 = getarrayitem_raw_i(p0, i0, descr=chararraydescr) i1 = int_add(i0, 1) i2 = int_le(i1, 16) guard_true(i2) [p0, i0] jump(p0,i1) """ loop = self.parse_loop(ops) - vopt = self.init_packset(loop,1) + vopt, graph = self.init_packset(loop,1) self.assert_independent(4,8) assert vopt.packset is not None - assert len(vopt.dependency_graph.memory_refs) == 2 + assert len(graph.memory_refs) == 2 assert len(vopt.packset.packs) == 1 def test_packset_init_raw_load_not_adjacent_and_adjacent(self): @@ -642,8 +678,8 @@ jump(p0,i0) """ loop = self.parse_loop(ops) - vopt = self.init_packset(loop,3) - assert len(vopt.dependency_graph.memory_refs) == 4 + vopt, graph = self.init_packset(loop,3) + assert len(graph.memory_refs) == 4 assert len(vopt.packset.packs) == 0 ops = """ [p0,i0] @@ -652,8 +688,8 @@ jump(p0,i2) """ loop = self.parse_loop(ops) - vopt = self.init_packset(loop,3) - assert len(vopt.dependency_graph.memory_refs) == 4 + vopt, graph = self.init_packset(loop,3) + assert len(graph.memory_refs) == 4 assert len(vopt.packset.packs) == 3 for i in range(3): x = (i+1)*2 @@ -667,24 +703,24 @@ i1 = int_add(i0, 1) i2 = int_le(i1, 16) guard_true(i2) [p0, i0] - i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i3 = getarrayitem_raw_i(p0, i1, descr=chararraydescr) jump(p0,i1) """ loop = self.parse_loop(ops) - vopt = self.init_packset(loop,15) - assert len(vopt.dependency_graph.memory_refs) == 16 + vopt, graph = self.init_packset(loop,15) + assert len(graph.memory_refs) == 16 assert len(vopt.packset.packs) == 15 # assure that memory refs are not adjacent for all for i in range(15): for j in range(15): try: if i-4 == j or i+4 == j: - mref1 = self.getmemref(i) - mref2 = self.getmemref(j) + mref1 = graph.getmemref(i) + mref2 = graph.getmemref(j) assert mref1.is_adjacent_to(mref2) else: - mref1 = self.getmemref(i) - mref2 = self.getmemref(j) + mref1 = graph.getmemref(i) + mref2 = graph.getmemref(j) assert not mref1.is_adjacent_to(mref2) except KeyError: pass @@ -697,25 +733,20 @@ def test_isomorphic_operations(self): ops_src = """ [p1,p0,i0] - i3 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i3 = getarrayitem_raw_i(p0, i0, descr=chararraydescr) i1 = int_add(i0, 1) i2 = int_le(i1, 16) - i4 = getarrayitem_raw(p0, i1, descr=chararraydescr) - i5 = getarrayitem_raw(p1, i1, descr=floatarraydescr) - i6 = getarrayitem_raw(p0, i1, descr=floatarraydescr) + i4 = getarrayitem_raw_i(p0, i1, descr=chararraydescr) + f5 = getarrayitem_raw_f(p1, i1, descr=floatarraydescr) + f6 = getarrayitem_raw_f(p0, i1, descr=floatarraydescr) guard_true(i2) [p0, i0] jump(p1,p0,i1) """ loop = self.parse_loop(ops_src) ops = loop.operations - assert isomorphic(ops[1], ops[4]) + assert isomorphic(ops[0], ops[3]) assert not isomorphic(ops[0], ops[1]) assert not isomorphic(ops[0], ops[5]) - # TODO strong assumptions do hold here? - #assert not isomorphic(ops[4], ops[5]) - #assert not isomorphic(ops[5], ops[6]) - #assert not isomorphic(ops[4], ops[6]) - #assert not isomorphic(ops[1], ops[6]) def test_packset_extend_simple(self): ops = """ @@ -723,33 +754,33 @@ i1 = int_add(i0, 1) i2 = int_le(i1, 16) guard_true(i2) [p0, i0] - i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i3 = getarrayitem_raw_i(p0, i1, descr=chararraydescr) i4 = int_add(i3, 1) jump(p0,i1) """ loop = self.parse_loop(ops) - vopt = self.extend_packset(loop,1) - assert len(vopt.dependency_graph.memory_refs) == 2 + vopt, graph = self.extend_packset(loop,1) + assert len(graph.memory_refs) == 2 self.assert_independent(5,10) assert len(vopt.packset.packs) == 2 - self.assert_packset_empty(vopt.packset, len(loop.operations), + self.assert_packset_empty(vopt.packset, + len(loop.operations), [(5,10), (4,9)]) def test_packset_extend_load_modify_store(self): ops = """ [p0,i0] - guard_early_exit() [] i1 = int_add(i0, 1) i2 = int_le(i1, 16) guard_true(i2) [p0, i0] - i3 = getarrayitem_raw(p0, i1, descr=chararraydescr) + i3 = getarrayitem_raw_i(p0, i1, descr=chararraydescr) i4 = int_mul(i3, 2) setarrayitem_raw(p0, i1, i4, descr=chararraydescr) jump(p0,i1) """ loop = self.parse_loop(ops) - vopt = self.extend_packset(loop,1) - assert len(vopt.dependency_graph.memory_refs) == 4 + vopt, graph = self.extend_packset(loop,1) + assert len(graph.memory_refs) == 4 self.assert_independent(4,10) self.assert_independent(5,11) self.assert_independent(6,12) @@ -763,15 +794,18 @@ ('int',2, [(0,(2,4)),(1,(6,8))]), ('singlefloat',1,[(0,(2,4,6,8))])]) def test_packset_combine_simple(self,descr,packs,packidx): + suffix = '_i' + if 'float' in descr: + suffix = '_f' ops = """ [p0,i0] - i3 = getarrayitem_raw(p0, i0, descr={descr}arraydescr) + i3 = getarrayitem_raw{suffix}(p0, i0, descr={descr}arraydescr) i1 = int_add(i0,1) jump(p0,i1) - """.format(descr=descr) + """.format(descr=descr,suffix=suffix) loop = self.parse_loop(ops) - vopt = self.combine_packset(loop,3) - assert len(vopt.dependency_graph.memory_refs) == 4 + vopt, graph = self.combine_packset(loop,3) + assert len(graph.memory_refs) == 4 assert len(vopt.packset.packs) == packs for i,t in packidx: self.assert_pack(vopt.packset.packs[i], t) @@ -832,7 +866,6 @@ def test_packset_vector_operation(self, op, descr, stride): ops = """ [p0,p1,p2,i0] - guard_early_exit() [] i1 = int_add(i0, {stride}) i10 = int_le(i1, 128) guard_true(i10) [] @@ -864,7 +897,6 @@ def test_schedule_vector_operation(self, op, descr, stride): ops = """ [p0,p1,p2,i0] # 0 - guard_early_exit() [] i10 = int_le(i0, 128) # 1, 8, 15, 22 guard_true(i10) [p0,p1,p2,i0] # 2, 9, 16, 23 i2 = getarrayitem_raw(p0, i0, descr={descr}arraydescr) # 3, 10, 17, 24 @@ -882,8 +914,8 @@ i11 = int_le(i1, 128) guard_true(i11) [] i12 = int_add(i1, {stride}) - v1 = vec_getarrayitem_raw(p0, i0, 2, descr={descr}arraydescr) - v2 = vec_getarrayitem_raw(p1, i0, 2, descr={descr}arraydescr) + v1 = vec_getarrayitem_raw(p0, i0, descr={descr}arraydescr) + v2 = vec_getarrayitem_raw(p1, i0, descr={descr}arraydescr) v3 = {op}(v1,v2) vec_setarrayitem_raw(p2, i0, v3, descr={descr}arraydescr) jump(p0,p1,p2,i12) @@ -895,7 +927,6 @@ def test_vschedule_trace_1(self): ops = """ [i0, i1, i2, i3, i4] - guard_early_exit() [] i6 = int_mul(i0, 8) i7 = raw_load(i2, i6, descr=arraydescr) i8 = raw_load(i3, i6, descr=arraydescr) @@ -928,7 +959,6 @@ def test_collapse_index_guard_1(self): ops = """ [p0,i0] - guard_early_exit() [p0,i0] i1 = getarrayitem_raw(p0, i0, descr=chararraydescr) i2 = int_add(i0, 1) i3 = int_lt(i2, 102) @@ -949,7 +979,7 @@ {dead_code} i500 = int_add(i0, 16) i501 = int_lt(i2, 102) - i1 = vec_getarrayitem_raw(p0, i0, 16, descr=chararraydescr) + v10[16xi8] = vec_getarrayitem_raw(p0, i0, descr=chararraydescr) jump(p0,i2) """.format(dead_code=dead_code) vopt = self.schedule(self.parse_loop(ops),15,with_guard_opt=True) @@ -958,7 +988,6 @@ def test_too_small_vector(self): ops = """ [p0,i0] - guard_early_exit() [p0,i0] i1 = getarrayitem_raw(p0, 0, descr=chararraydescr) # constant index i2 = getarrayitem_raw(p0, 1, descr=chararraydescr) # constant index i4 = int_add(i1, i2) @@ -976,7 +1005,6 @@ def test_constant_expansion(self): ops = """ [p0,i0] - guard_early_exit() [p0,i0] i1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) i4 = int_sub(i1, 42) i3 = int_add(i0,1) @@ -987,8 +1015,8 @@ opt=""" [p0,i0] label(p0,i0) - v3 = vec_int_expand(42, 2) - label(p0,i0,v3) + v3[2xf64] = vec_expand_f(42.0) + label(p0,i0,v3[2xf64]) i20 = int_add(i0, 1) i30 = int_lt(i20, 10) i2 = int_add(i0, 2) @@ -996,9 +1024,9 @@ guard_true(i3) [p0,i0] i4 = int_add(i0, 2) i5 = int_lt(i2, 10) - v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr) - v2 = vec_int_sub(v1, v3) - jump(p0,i2,v3) + v1[2xf64] = vec_getarrayitem_raw(p0, i0, descr=floatarraydescr) + v2[2xf64] = vec_int_sub(v1[2xf64], v3[2xf64]) + jump(p0,i2,v3[2xf64]) """ vopt = self.vectorize(self.parse_loop(ops),1) self.assert_equal(vopt.loop, self.parse_loop(opt,add_label=False)) @@ -1006,7 +1034,6 @@ def test_variable_expansion(self): ops = """ [p0,i0,f3] - guard_early_exit() [p0,i0] f1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) f4 = int_add(f1, f3) i3 = int_add(i0,1) @@ -1017,8 +1044,8 @@ opt=""" [p0,i0,f3] label(p0,i0,f3) - v3 = vec_float_expand(f3,2) - label(p0,i0,f3,v3) + v3[2xf64] = vec_expand_f(f3) + label(p0,i0,f3,v3[2xf64]) i20 = int_add(i0, 1) i30 = int_lt(i20, 10) i2 = int_add(i0, 2) @@ -1026,9 +1053,9 @@ guard_true(i3) [p0,i0,f3] i4 = int_add(i0, 2) i5 = int_lt(i2, 10) - v1 = vec_getarrayitem_raw(p0, i0, 2, descr=floatarraydescr) - v2 = vec_int_add(v1, v3) - jump(p0,i2,f3,v3) + v1[2xf64] = vec_getarrayitem_raw(p0, i0, descr=floatarraydescr) + v2[2xf64] = vec_int_add(v1[2xf64], v3[2xf64]) + jump(p0,i2,f3,v3[2xf64]) """ vopt = self.vectorize(self.parse_loop(ops),1) self.assert_equal(vopt.loop, self.parse_loop(opt, add_label=False)) @@ -1036,7 +1063,6 @@ def test_accumulate_basic(self): trace = """ [p0, i0, f0] - guard_early_exit() [p0, i0, f0] f1 = raw_load(p0, i0, descr=floatarraydescr) f2 = float_add(f0, f1) i1 = int_add(i0, 8) @@ -1063,7 +1089,6 @@ def test_element_f45_in_guard_failargs(self): ops = """ [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] - guard_early_exit() [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41] f45 = raw_load(i21, i44, descr=floatarraydescr) guard_not_invalidated() [p38, p12, p9, p14, f45, p39, i37, i44, f35, i40, p42, i43, None, i28, p36, i41] i46 = int_add(i44, 8) @@ -1107,7 +1132,6 @@ def test_shrink_vector_size(self): ops = """ [p0,p1,i1] - guard_early_exit() [] f1 = getarrayitem_raw(p0, i1, descr=floatarraydescr) i2 = cast_float_to_singlefloat(f1) setarrayitem_raw(p1, i1, i2, descr=singlefloatarraydescr) @@ -1143,7 +1167,6 @@ def test_castup_arith_castdown(self): ops = """ [p0,p1,p2,i0,i4] - guard_early_exit() [] i10 = raw_load(p0, i0, descr=singlefloatarraydescr) i1 = int_add(i0, 4) i11 = raw_load(p1, i1, descr=singlefloatarraydescr) @@ -1196,7 +1219,6 @@ def test_truediv_abs_neg_float(self): ops = """ [f9,p10,i11,p4,i12,p2,p5,p13,i14,p7,i15,p8,i16,f17,i18,i19] - guard_early_exit() [p8, p7, p5, p4, p2, f9, i12, i11, p10, i15, i14, p13] f20 = raw_load(i16, i12, descr=floatarraydescr) guard_not_invalidated() [p8, p7, p5, p4, p2, f20, None, i12, i11, p10, i15, i14, p13] i23 = int_add(i12, 8) @@ -1216,7 +1238,6 @@ def test_axis_sum(self): trace = """ [i1, p10, i11, p8, i12, p3, p4, p13, i14, i15, p6, p9, i16, i17, i18, i19, i20, i21, i22, i23] - guard_early_exit() [i1, p9, p8, p6, p4, p3, i11, i15, p13, i12, i14, p10] f24 = raw_load(i16, i12, descr=floatarraydescr) guard_not_invalidated() [i1, p9, p8, p6, p4, p3, f24, i11, i15, p13, i12, i14, p10] i26 = int_add(i12, 8) @@ -1246,7 +1267,6 @@ def test_cast_1(self): trace = """ [i9, i10, p2, p11, i12, i13, p4, p5, p14, i15, p8, i16, p17, i18, i19, i20, i21, i22, i23] - guard_early_exit() [p8, p5, p4, p2, p17, i13, i12, i10, i19, p14, p11, i18, i15, i16, i9] i24 = raw_load(i20, i16, descr=singlefloatarraydescr) guard_not_invalidated() [p8, p5, p4, p2, i24, p17, i13, i12, i10, i19, p14, p11, i18, i15, i16, None] i27 = int_add(i16, 4) @@ -1269,7 +1289,6 @@ def test_all_guard(self): trace = """ [p0, p3, i4, i5, i6, i7] - guard_early_exit() [p0, p3, i5, i4] f8 = raw_load(i6, i5, descr=floatarraydescr) guard_not_invalidated() [p0, f8, p3, i5, i4] i9 = cast_float_to_int(f8) @@ -1287,7 +1306,6 @@ def test_max(self): trace = """ [p3, i4, p2, i5, f6, i7, i8] - guard_early_exit() [p2, f6, i4, i5, p3] f9 = raw_load(i7, i5, descr=floatarraydescr) guard_not_invalidated() [p2, f9, f6, i4, i5, p3] i10 = float_ge(f6, f9) @@ -1307,7 +1325,6 @@ def test_abc(self): trace=""" [p0, p1, p5, p6, p7, p12, p13, i14, i15, i16, i17, i18, i19, i20] - guard_early_exit() [] debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #117 LOAD_NAME') guard_not_invalidated(descr=) [p1, p0, p5, p6, p7, p12, p13] debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #120 LOAD_CONST') @@ -1354,7 +1371,6 @@ def test_bug1(self): trace=""" [p0, p1, p6, p7, p11, i83, f57, f61, f65, f70, f78, f81, i48, i56, p46] - guard_early_exit(descr=) [p1, p0, p6, p7, p11, f81, f78, f70, f65, f61, f57, i83] guard_not_invalidated(descr=) [p1, p0, p6, p7, p11, f81, f78, f70, f65, f61, f57, i83] i91 = int_lt(i83, i48) guard_true(i91, descr=) [p1, p0, p6, p7, p11, i48, f81, f78, f70, f65, f61, f57, i83] @@ -1389,7 +1405,6 @@ def test_1(self): trace = """ [p0, p1, p6, p7, i13, p14, p15] - guard_early_exit(descr=) [p1, p0, p6, p7, i13] guard_not_invalidated(descr=) [p1, p0, p6, p7, i13] i17 = int_lt(i13, 10000) guard_true(i17, descr=) [p1, p0, p6, p7, i13] diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -176,7 +176,6 @@ if vsize == 0 or byte_count == 0 or loop.label.getopnum() != rop.LABEL: # stop, there is no chance to vectorize this trace # we cannot optimize normal traces (if there is no label) - import pdb; pdb. set_trace() raise NotAVectorizeableLoop() # find index guards and move to the earliest position @@ -188,8 +187,6 @@ # unroll self.unroll_count = self.get_unroll_count(vsize) self.unroll_loop_iterations(loop, self.unroll_count) - loop.operations = self.get_newoperations() - self.clear_newoperations(); # vectorize graph = DependencyGraph(loop) @@ -210,8 +207,6 @@ def unroll_loop_iterations(self, loop, unroll_count): """ Unroll the loop X times. unroll_count + 1 = unroll_factor """ numops = len(loop.operations) - label_op = loop.label - jump_op = loop.jump # use the target token of the label #target_token = label_op.getdescr() #if not we_are_translated(): @@ -223,33 +218,32 @@ # jump_op.setdescr(target_token) #assert jump_op.is_final() - self.emit_unrolled_operation(label_op) + #self.emit_unrolled_operation(label_op) + + #for i in range(0,numops): + # op = loop.operations[i].copy() + # if op.is_guard(): + # assert isinstance(op, GuardResOp) + # failargs = renamer.rename_failargs(op, clone=True) + # snapshot = renamer.rename_rd_snapshot(op.rd_snapshot, clone=True) + # op.setfailargs(failargs) + # op.rd_snapshot = snapshot + # operations.append(op) + # self.emit_unrolled_operation(op) renamer = Renamer() - operations = [] - for i in range(1,numops-1): - op = loop.operations[i].copy() - if op.is_guard(): - assert isinstance(op, GuardResOp) - failargs = renamer.rename_failargs(op, clone=True) - snapshot = renamer.rename_rd_snapshot(op.rd_snapshot, clone=True) - op.setfailargs(failargs) - op.rd_snapshot = snapshot - operations.append(op) - self.emit_unrolled_operation(op) - + operations = loop.operations + unrolled = [] prohibit_opnums = (rop.GUARD_FUTURE_CONDITION, - rop.GUARD_EARLY_EXIT, rop.GUARD_NOT_INVALIDATED) - - orig_jump_args = jump_op.getarglist()[:] + orig_jump_args = loop.jump.getarglist()[:] # it is assumed that #label_args == #jump_args label_arg_count = len(orig_jump_args) for u in range(unroll_count): # fill the map with the renaming boxes. keys are boxes from the label for i in range(label_arg_count): - la = label_op.getarg(i) - ja = jump_op.getarg(i) + la = loop.label.getarg(i) + ja = loop.jump.getarg(i) ja = renamer.rename_box(ja) if la != ja: renamer.start_renaming(la, ja) @@ -284,17 +278,18 @@ renamer.rename_failargs(copied_op, clone=True) copied_op.setfailargs(renamed_failargs) # - self.emit_unrolled_operation(copied_op) + unrolled.append(copied_op) # the jump arguments have been changed # if label(iX) ... jump(i(X+1)) is called, at the next unrolled loop # must look like this: label(i(X+1)) ... jump(i(X+2)) - args = jump_op.getarglist() + args = loop.jump.getarglist() for i, arg in enumerate(args): value = renamer.rename_box(arg) - jump_op.setarg(i, value) + loop.jump.setarg(i, value) # - self.emit_unrolled_operation(jump_op) + #self.emit_unrolled_operation(jump_op) + loop.operations = operations + unrolled def linear_find_smallest_type(self, loop): # O(#operations) @@ -456,14 +451,7 @@ fail = True check[left] = None check[right] = None - accum = pack.accum - if accum: - self.packset.accum_vars[accum.var] = accum.pos - - print " %dx %s " % (len(pack.operations), - pack.operations[0].op.getopname()) - if accum: - print " accumulates!" + print " ", pack if fail: assert False @@ -537,9 +525,9 @@ modify_later.append(prev_node) else: for path in prev_node.iterate_paths(None, backwards=True, blacklist=True): - if not path.is_always_pure(exclude_first=True): - path.set_schedule_priority(90) + if not path.is_always_pure(): valid = False + else: if path.last() in zero_deps: del zero_deps[path.last()] if not valid: @@ -559,34 +547,25 @@ for node in zero_deps.keys(): earlyexit.edge_to(node) - # TODO self.relax_guard_to(guard_node, ee_guard_node) + self.mark_guard(guard_node, loop) if one_valid: return graph return None - def relax_guard_to(self, guard_node, other_node): - """ Relaxes a guard operation to an earlier guard. """ - # clone this operation object. if the vectorizer is - # not able to relax guards, it won't leave behind a modified operation - tgt_op = guard_node.getoperation().clone() - guard_node.op = tgt_op - - op = other_node.getoperation() - assert isinstance(tgt_op, GuardResOp) + def mark_guard(self, node, loop): + """ Marks this guard as an early exit! """ + op = node.getoperation() assert isinstance(op, GuardResOp) - olddescr = op.getdescr() descr = None - guard_true_false = tgt_op.getopnum() in (rop.GUARD_TRUE, rop.GUARD_FALSE) - if guard_true_false: + if op.getopnum() in (rop.GUARD_TRUE, rop.GUARD_FALSE): descr = CompileLoopVersionDescr() else: descr = ResumeAtLoopHeaderDescr() - if olddescr: - descr.copy_all_attributes_from(olddescr) + if op.getdescr(): + descr.copy_all_attributes_from(op.getdescr()) # - tgt_op.setdescr(descr) - tgt_op.setfailargs(op.getfailargs()[:]) - + op.setdescr(descr) + op.setfailargs(loop.inputargs) class CostModel(object): """ Utility to estimate the savings for the new trace loop. @@ -687,7 +666,6 @@ if forward and origin_pack.is_accumulating(): # in this case the splitted accumulator must # be combined. This case is not supported - import pdb; pdb. set_trace() raise NotAVectorizeableLoop() # if self.contains_pair(lnode, rnode): diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -113,26 +113,26 @@ jump.setdescr(token) -def index_of_first(opnum, operations, pass_by=0): - """ returns the position of the first operation matching the opnum. - Or -1 if non is found - """ - for i,op in enumerate(operations): - if op.getopnum() == opnum: - if pass_by == 0: - return i - else: - pass_by -= 1 - return -1 +#def index_of_first(opnum, operations, pass_by=0): +# """ returns the position of the first operation matching the opnum. +# Or -1 if non is found +# """ +# for i,op in enumerate(operations): +# if op.getopnum() == opnum: +# if pass_by == 0: +# return i +# else: +# pass_by -= 1 +# return -1 +# +#def find_first_index(self, opnum, pass_by=0): +# """ return the first index of the operation having the same opnum or -1 """ +# return index_of_first(opnum, self.operations, pass_by) +# +#def find_first(self, opnum, pass_by=0): +# index = self.find_first_index(opnum, pass_by) +# if index != -1: +# return self.operations[index] +# return None -def find_first_index(self, opnum, pass_by=0): - """ return the first index of the operation having the same opnum or -1 """ - return index_of_first(opnum, self.operations, pass_by) -def find_first(self, opnum, pass_by=0): - index = self.find_first_index(opnum, pass_by) - if index != -1: - return self.operations[index] - return None - - From noreply at buildbot.pypy.org Fri Sep 18 12:54:51 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 18 Sep 2015 12:54:51 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: pushing forward to 3/4 passing (yay) Message-ID: <20150918105451.801521C0933@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79684:cbfcb6aca9d7 Date: 2015-09-18 12:55 +0200 http://bitbucket.org/pypy/pypy/changeset/cbfcb6aca9d7/ Log: pushing forward to 3/4 passing (yay) diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -160,19 +160,9 @@ @staticmethod def of(boolarg, operations, index, index_vars): guard_op = operations[index] - i = index - 1 - # most likely hit in the first iteration - while i > 0: - op = operations[i] - if op.result and op.result == boolarg: - if rop.INT_LT <= op.getopnum() <= rop.INT_GE: - cmp_op = op - break - return None - i -= 1 - else: - raise AssertionError("guard_true/false first arg not defined") - # + cmp_op = guard_op.getarg(0) + if not (rop.INT_LT <= cmp_op.getopnum() <= rop.INT_GE): + return None return Guard(index, guard_op, cmp_op, index_vars) class GuardStrengthenOpt(object): diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -90,27 +90,29 @@ whenever their dependency count drops to zero. Keeps worklist sorted (see priority) """ worklist = state.worklist - for dep in node.provides()[:]: # COPY - to = dep.to - node.remove_edge_to(to) - if not to.emitted and to.depends_count() == 0: + provides = node.provides()[:] + for dep in provides: # COPY + target = dep.to + node.remove_edge_to(target) + if not target.emitted and target.depends_count() == 0: # sorts them by priority i = len(worklist)-1 while i >= 0: - itnode = worklist[i] - c = (itnode.priority - to.priority) - if c < 0: # meaning itnode.priority < to.priority: - worklist.insert(i+1, to) + cur = worklist[i] + c = (cur.priority - target.priority) + if c < 0: # meaning itnode.priority < target.priority: + worklist.insert(i+1, target) break elif c == 0: # if they have the same priority, sort them # using the original position in the trace - if itnode.getindex() < to.getindex(): - worklist.insert(i, to) + if target.getindex() < cur.getindex(): + worklist.insert(i+1, target) break i -= 1 else: - worklist.insert(0, to) + print "insert at 0", target + worklist.insert(0, target) node.clear_dependencies() node.emitted = True if not node.is_imaginary(): @@ -528,7 +530,7 @@ for i,arg in enumerate(failargs): if arg is None: continue - accum = state.accumulation.get(arg, None) + accum = self.accumulation.get(arg, None) if accum: assert isinstance(accum, AccumPack) accum.attach_accum_info(descr.rd_accum_list, i) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -143,7 +143,6 @@ return graph def assert_independent(self, a, b): - # XXX a -= 1 b -= 1 a = self.last_graph.getnode(a) @@ -151,7 +150,6 @@ assert a.independent(b), "{a} and {b} are dependent!".format(a=a,b=b) def assert_dependent(self, a, b): - # XXX a -= 1 b -= 1 a = self.last_graph.getnode(a) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -789,10 +789,11 @@ [(6,12), (5,11), (4,10)]) @pytest.mark.parametrize("descr,packs,packidx", - [('char',1, [(0,(2,4,6,8))]), - ('float',2, [(0,(2,4)),(1,(6,8))]), - ('int',2, [(0,(2,4)),(1,(6,8))]), - ('singlefloat',1,[(0,(2,4,6,8))])]) + [('char', 0, []), + ('float', 2, [(0,(1,3)),(1,(5,7))]), + ('', 2, [(0,(1,3)),(1,(5,7))]), + ('float32', 1, [(0,(1,3,5,7))]), + ]) def test_packset_combine_simple(self,descr,packs,packidx): suffix = '_i' if 'float' in descr: @@ -811,7 +812,7 @@ self.assert_pack(vopt.packset.packs[i], t) @pytest.mark.parametrize("descr,stride,packs,suffix", - [('char',1,1,'_i'),('float',8,4,'_f'),('int',8,4,'_i'),('float32',4,2,'_i')]) + [('char',1,0,'_i'),('float',8,4,'_f'),('',8,4,'_i'),('float32',4,2,'_i')]) def test_packset_combine_2_loads_in_trace(self, descr, stride, packs, suffix): ops = """ [p0,i0] @@ -822,8 +823,8 @@ jump(p0,i2) """.format(type=descr,stride=stride,suffix=suffix) loop = self.parse_loop(ops) - vopt = self.combine_packset(loop,3) - assert len(vopt.dependency_graph.memory_refs) == 8 + vopt, graph = self.combine_packset(loop,3) + assert len(graph.memory_refs) == 8 assert len(vopt.packset.packs) == packs def test_packset_combine_no_candidates_packset_empty(self): @@ -840,12 +841,14 @@ ops = """ [p0,i0] - i3 = getarrayitem_raw(p0, i0, descr=floatarraydescr) - jump(p0,i3) + f3 = getarrayitem_raw_f(p0, i0, descr=floatarraydescr) + jump(p0,i0) """ + loop = self.parse_loop(ops) try: - loop = self.parse_loop(ops) self.combine_packset(loop,15) + pytest.fail("combine should raise an exception if no pack " + "statements are present") except NotAVectorizeableLoop: pass @@ -856,14 +859,17 @@ ('float_add','float',8), ('float_sub','float',8), ('float_mul','float',8), - ('float_add','singlefloat',4), - ('float_sub','singlefloat',4), - ('float_mul','singlefloat',4), - ('int_add','int',8), - ('int_sub','int',8), - ('int_mul','int',8), + ('float_add','float32',4), + ('float_sub','float32',4), + ('float_mul','float32',4), + ('int_add','',8), + ('int_sub','',8), + ('int_mul','',8), ]) def test_packset_vector_operation(self, op, descr, stride): + suffix = '_i' + if 'float' in descr: + suffix = '_f' ops = """ [p0,p1,p2,i0] i1 = int_add(i0, {stride}) @@ -874,52 +880,57 @@ i4 = {op}(i2,i3) raw_store(p2, i0, i4, descr={descr}arraydescr) jump(p0,p1,p2,i1) - """.format(op=op,descr=descr,stride=stride) + """.format(op=op,descr=descr,stride=stride,suffix=suffix) loop = self.parse_loop(ops) - vopt = self.combine_packset(loop,3) - assert len(vopt.dependency_graph.memory_refs) == 12 + vopt, graph = self.combine_packset(loop,3) + assert len(graph.memory_refs) == 12 if stride == 8: assert len(vopt.packset.packs) == 8 else: - assert len(vopt.packset.packs) == 4 - - for opindices in [(5,12,19,26),(6,13,20,27), - (7,14,21,28),(4,11,18,25)]: + if descr != 'char': + assert len(vopt.packset.packs) == 4 + if descr == 'char': + return + for opindices in [(4,11,18,25),(5,12,19,26), + (6,13,20,27),(4,11,18,25)]: self.assert_has_pack_with(vopt.packset, opindices) @pytest.mark.parametrize('op,descr,stride', [('float_add','float',8), ('float_sub','float',8), ('float_mul','float',8), - ('int_add','int',8), - ('int_sub','int',8), + ('int_add','',8), + ('int_sub','',8), ]) def test_schedule_vector_operation(self, op, descr, stride): + suffix = '_i' + if 'float' in descr: + suffix = '_f' ops = """ [p0,p1,p2,i0] # 0 i10 = int_le(i0, 128) # 1, 8, 15, 22 guard_true(i10) [p0,p1,p2,i0] # 2, 9, 16, 23 - i2 = getarrayitem_raw(p0, i0, descr={descr}arraydescr) # 3, 10, 17, 24 - i3 = getarrayitem_raw(p1, i0, descr={descr}arraydescr) # 4, 11, 18, 25 + i2 = getarrayitem_raw{suffix}(p0, i0, descr={descr}arraydescr) # 3, 10, 17, 24 + i3 = getarrayitem_raw{suffix}(p1, i0, descr={descr}arraydescr) # 4, 11, 18, 25 i4 = {op}(i2,i3) # 5, 12, 19, 26 setarrayitem_raw(p2, i0, i4, descr={descr}arraydescr) # 6, 13, 20, 27 i1 = int_add(i0, {stride}) # 7, 14, 21, 28 jump(p0,p1,p2,i1) # 29 - """.format(op=op,descr=descr,stride=1) # stride getarray is always 1 + """.format(op=op,descr=descr,stride=1,suffix=suffix) vops = """ [p0,p1,p2,i0] i10 = int_le(i0, 128) - guard_true(i10) [] + guard_true(i10) [p0,p1,p2,i0] i1 = int_add(i0, {stride}) i11 = int_le(i1, 128) - guard_true(i11) [] + guard_true(i11) [p0,p1,p2,i1] i12 = int_add(i1, {stride}) - v1 = vec_getarrayitem_raw(p0, i0, descr={descr}arraydescr) - v2 = vec_getarrayitem_raw(p1, i0, descr={descr}arraydescr) + v1 = vec_getarrayitem_raw{suffix}(p0, i0, descr={descr}arraydescr) + v2 = vec_getarrayitem_raw{suffix}(p1, i0, descr={descr}arraydescr) v3 = {op}(v1,v2) vec_setarrayitem_raw(p2, i0, v3, descr={descr}arraydescr) jump(p0,p1,p2,i12) - """.format(op='vec_'+op,descr=descr,stride=1) + """.format(op='vec_'+op,descr=descr,stride=1,suffix=suffix) loop = self.parse_loop(ops) vopt = self.schedule(loop, 1) self.assert_equal(loop, self.parse_loop(vops)) @@ -928,8 +939,8 @@ ops = """ [i0, i1, i2, i3, i4] i6 = int_mul(i0, 8) - i7 = raw_load(i2, i6, descr=arraydescr) - i8 = raw_load(i3, i6, descr=arraydescr) + i7 = raw_load_i(i2, i6, descr=arraydescr) + i8 = raw_load_i(i3, i6, descr=arraydescr) i9 = int_add(i7, i8) raw_store(i4, i6, i9, descr=arraydescr) i11 = int_add(i0, 1) @@ -940,26 +951,27 @@ opt=""" [i0, i1, i2, i3, i4] i11 = int_add(i0, 1) + i12 = int_lt(i11, i1) + guard_true(i12) [i0,i1,i2,i3,i4] i6 = int_mul(i0, 8) - i12 = int_lt(i11, i1) - guard_true(i12) [] i13 = int_add(i11, 1) + i18 = int_lt(i13, i1) + guard_true(i18) [i11,i1,i2,i3,i4] i14 = int_mul(i11, 8) - i18 = int_lt(i13, i1) - guard_true(i18) [] - v19 = vec_raw_load(i2, i6, 2, descr=arraydescr) - v20 = vec_raw_load(i3, i6, 2, descr=arraydescr) - v21 = vec_int_add(v19, v20) + v19[2xi64] = vec_raw_load_i(i2, i6, descr=arraydescr) + v20[2xi64] = vec_raw_load_i(i3, i6, descr=arraydescr) + v21[2xi64] = vec_int_add(v19, v20) vec_raw_store(i4, i6, v21, descr=arraydescr) jump(i13, i1, i2, i3, i4) """ - vopt = self.schedule(self.parse_loop(ops),1) - self.assert_equal(vopt.loop, self.parse_loop(opt)) + loop = self.parse_loop(ops) + vopt = self.schedule(loop,1) + self.assert_equal(loop, self.parse_loop(opt)) def test_collapse_index_guard_1(self): ops = """ [p0,i0] - i1 = getarrayitem_raw(p0, i0, descr=chararraydescr) + i1 = getarrayitem_raw_i(p0, i0, descr=chararraydescr) i2 = int_add(i0, 1) i3 = int_lt(i2, 102) guard_true(i3) [p0,i0] @@ -979,11 +991,12 @@ {dead_code} i500 = int_add(i0, 16) i501 = int_lt(i2, 102) - v10[16xi8] = vec_getarrayitem_raw(p0, i0, descr=chararraydescr) + v10[16xi8] = vec_getarrayitem_raw_i(p0, i0, descr=chararraydescr) jump(p0,i2) """.format(dead_code=dead_code) - vopt = self.schedule(self.parse_loop(ops),15,with_guard_opt=True) - self.assert_equal(vopt.loop, self.parse_loop(opt)) + loop = self.parse_loop(ops) + vopt = self.schedule(loop,15,with_guard_opt=True) + self.assert_equal(loop, self.parse_loop(opt)) def test_too_small_vector(self): ops = """ diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -369,6 +369,7 @@ if match: counter = int(match.group(1)) countdict = val._repr_memo + assert val not in countdict._d countdict._d[val] = counter if countdict.counter < counter: countdict.counter = counter From noreply at buildbot.pypy.org Fri Sep 18 14:03:21 2015 From: noreply at buildbot.pypy.org (Raemi) Date: Fri, 18 Sep 2015 14:03:21 +0200 (CEST) Subject: [pypy-commit] pypy stmgc-c8-gcc: update TODO Message-ID: <20150918120321.90CAB1C1F84@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: stmgc-c8-gcc Changeset: r79685:6f9104e6177d Date: 2015-09-18 14:03 +0200 http://bitbucket.org/pypy/pypy/changeset/6f9104e6177d/ Log: update TODO diff --git a/TODO b/TODO --- a/TODO +++ b/TODO @@ -1,25 +1,50 @@ ------------------------------------------------------------ -annotating and rtyping pixie with --jit=off and 1 thread (no -conflicts) is: -STM: 148s -pypy2.6: 91.3s +annotating and rtyping pixie: -full mapdict and methodcache bring STM down to 130s, which -is a reasonable 40% overhead. --> think about fixing mapdict -and methodcache with STM +== with 1 thread: +- pypy26: +[Timer] annotate --- 27.6 s +[Timer] rtype_lltype --- 33.5 s +[Timer] ========================================= +[Timer] Total: --- 61.1 s -This difference may also explain a similar with-jit result: -STM: 96 -pypy2.6: 64.5s -which gets even worse with more than 1 thread: -STM: 116s (4 threads) -pypy2.6: 64s (still using only 1 thread) +- pypystm, with dict/set: +[Timer] annotate --- 41.3 s +[Timer] rtype_lltype --- 49.1 s +[Timer] ========================================= +[Timer] Total: --- 90.4 s + +- pypystm, with stmdict/stmset: +[Timer] annotate --- 41.8 s +[Timer] rtype_lltype --- 49.5 s +[Timer] ========================================= +[Timer] Total: --- 91.3 s + +== with 4 threads: +- pypy26: +[Timer] annotate --- 28.2 s +[Timer] rtype_lltype --- 36.3 s +[Timer] ========================================= +[Timer] Total: --- 64.4 s + +- pypystm, with dict/set: +[Timer] annotate --- 42.1 s +[Timer] rtype_lltype --- 65.8 s +[Timer] ========================================== +[Timer] Total: --- 107.9 s + +- pypystm, with stmdict/stmset: +[Timer] annotate --- 41.5 s +[Timer] rtype_lltype --- 62.5 s +[Timer] ========================================== +[Timer] Total: --- 103.9 s TODOs: -1) stmdict/stmset need strategies (only ~2% perf here) -2) methodcache & mapdict for generally better no-jit performance -3) theoretically, more threads shouldn't take even longer +- stmdict/set with strategies: ~1% perf... +- 87% overhead when using 4 threads on STM vs. 1 thread pypy26 + or 26% overhead of STM 4 threads vs. STM 1 thread +--> make rtyping less conflicting? ------------------------------------------------------------ From noreply at buildbot.pypy.org Fri Sep 18 16:03:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 16:03:31 +0200 (CEST) Subject: [pypy-commit] pypy default: check_correct_type() should also be true in getfield_gc_x. Message-ID: <20150918140331.8958B1C13AE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79686:3b890eadde77 Date: 2015-09-18 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/3b890eadde77/ Log: check_correct_type() should also be true in getfield_gc_x. diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -600,16 +600,22 @@ @specialize.argtype(1) def bh_getfield_gc_i(self, struct, fielddescr): ofs, size, sign = self.unpack_fielddescr_size(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_int_at_mem(struct, ofs, size, sign) @specialize.argtype(1) def bh_getfield_gc_r(self, struct, fielddescr): ofs = self.unpack_fielddescr(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_ref_at_mem(struct, ofs) @specialize.argtype(1) def bh_getfield_gc_f(self, struct, fielddescr): ofs = self.unpack_fielddescr(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_float_at_mem(struct, ofs) bh_getfield_raw_i = bh_getfield_gc_i From noreply at buildbot.pypy.org Fri Sep 18 16:07:41 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 18 Sep 2015 16:07:41 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: (integration tests) six of them still failing, but the rest is working Message-ID: <20150918140741.361991C13AE@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79687:6877dfe0b4c0 Date: 2015-09-18 16:07 +0200 http://bitbucket.org/pypy/pypy/changeset/6877dfe0b4c0/ Log: (integration tests) six of them still failing, but the rest is working diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -1061,7 +1061,6 @@ var = self.var if self.is_identity(): return var - last_op = None if self.coefficient_mul != 1: args = [var, ConstInt(self.coefficient_mul)] var = ResOperation(rop.INT_MUL, args) @@ -1072,8 +1071,8 @@ opt.emit_operation(var) if self.constant > 0: args = [var, ConstInt(self.constant)] - vec = ResOperation(rop.INT_ADD, args) - opt.emit_operation(vec) + var = ResOperation(rop.INT_ADD, args) + opt.emit_operation(var) if self.constant < 0: args = [var, ConstInt(self.constant)] var = ResOperation(rop.INT_SUB, args) diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -242,7 +242,8 @@ index_var = self.index_vars.get(op, None) if index_var: if not index_var.is_identity(): - index_var.emit_operations(self, op) + var = index_var.emit_operations(self, op) + self.renamer.start_renaming(op, var) continue self.emit_operation(op) # diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -451,14 +451,14 @@ args[index] = vecop return vecop - vecop = OpHelpers.create_vec(arg.type, left.bytesize, left.signed) + vecop = OpHelpers.create_vec(arg.type, arg.bytesize, arg.signed) ops.append(vecop) for i,node in enumerate(pack.operations): op = node.getoperation() arg = op.getarg(index) arguments = [vecop, arg, ConstInt(i), ConstInt(1)] - vecop = OpHelpers.create_vec_pack(arg.type, arguments, left.bytesize, - left.signed, vecop.count+1) + vecop = OpHelpers.create_vec_pack(arg.type, arguments, vecop.bytesize, + vecop.signed, vecop.count+1) ops.append(vecop) state.expand(expandargs, vecop) @@ -838,12 +838,12 @@ class AccumPack(Pack): SUPPORTED = { rop.FLOAT_ADD: '+', - rop.INT_ADD: '+', + rop.INT_ADD: '+', rop.FLOAT_MUL: '*', } def __init__(self, nodes, operator, accum, position): - Pack.__init__(self, [left, right]) + Pack.__init__(self, nodes) self.accumulator = accum self.operator = operator self.position = position @@ -858,6 +858,11 @@ """ The accumulatoriable holding the seed value """ return self.accumulator + def reduce_init(self): + if self.operator == '*': + return 1 + return 0 + def attach_accum_info(self, descr, position, scalar): descr.rd_accum_list = AccumInfo(descr.rd_accum_list, position, self.operator, diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -42,7 +42,7 @@ assert node.independent(node) return self.last_graph - def parse_loop(self, ops, add_label=True, **kwargs): + def parse_loop(self, ops, add_label=True): loop = self.parse(ops, postprocess=self.postprocess) loop.operations = filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) token = JitCellToken() 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 @@ -18,7 +18,8 @@ from rpython.jit.metainterp.jitprof import EmptyProfiler from rpython.jit.metainterp.counter import DeterministicJitCounter from rpython.config.translationoption import get_combined_translation_config -from rpython.jit.metainterp.resoperation import rop, ResOperation, InputArgRef +from rpython.jit.metainterp.resoperation import (rop, ResOperation, + InputArgRef, AbstractValue) from rpython.jit.metainterp.optimizeopt.util import args_dict @@ -471,6 +472,7 @@ class BaseTest(object): def parse(self, s, boxkinds=None, want_fail_descr=True, postprocess=None): + AbstractValue._repr_memo.counter = 0 self.oparse = OpParser(s, self.cpu, self.namespace, 'lltype', boxkinds, None, False, postprocess) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -170,6 +170,11 @@ raise NotAProfitableLoop() gso = GuardStrengthenOpt(graph.index_vars) gso.propagate_all_forward(info, loop) + oplist = loop.operations + loop.operations = loop.prefix[:] + if loop.prefix_label: + loop.operations += [loop.prefix_label] + loop.operations += oplist return opt def assert_unroll_loop_equals(self, loop, expected_loop, \ @@ -990,7 +995,7 @@ guard_true(i3) [p0,i0] {dead_code} i500 = int_add(i0, 16) - i501 = int_lt(i2, 102) + i501 = int_lt(i500, 102) v10[16xi8] = vec_getarrayitem_raw_i(p0, i0, descr=chararraydescr) jump(p0,i2) """.format(dead_code=dead_code) @@ -1001,8 +1006,8 @@ def test_too_small_vector(self): ops = """ [p0,i0] - i1 = getarrayitem_raw(p0, 0, descr=chararraydescr) # constant index - i2 = getarrayitem_raw(p0, 1, descr=chararraydescr) # constant index + i1 = getarrayitem_raw_i(p0, 0, descr=chararraydescr) # constant index + i2 = getarrayitem_raw_i(p0, 1, descr=chararraydescr) # constant index i4 = int_add(i1, i2) i3 = int_add(i0,1) i5 = int_lt(i3, 10) @@ -1018,7 +1023,7 @@ def test_constant_expansion(self): ops = """ [p0,i0] - i1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) + i1 = getarrayitem_raw_i(p0, i0, descr=arraydescr) i4 = int_sub(i1, 42) i3 = int_add(i0,1) i5 = int_lt(i3, 10) @@ -1027,8 +1032,7 @@ """ opt=""" [p0,i0] - label(p0,i0) - v3[2xf64] = vec_expand_f(42.0) + v3[2xf64] = vec_expand_i(42) label(p0,i0,v3[2xf64]) i20 = int_add(i0, 1) i30 = int_lt(i20, 10) @@ -1036,19 +1040,20 @@ i3 = int_lt(i2, 10) guard_true(i3) [p0,i0] i4 = int_add(i0, 2) - i5 = int_lt(i2, 10) - v1[2xf64] = vec_getarrayitem_raw(p0, i0, descr=floatarraydescr) + i5 = int_lt(i4, 10) + v1[2xf64] = vec_getarrayitem_raw_i(p0, i0, descr=arraydescr) v2[2xf64] = vec_int_sub(v1[2xf64], v3[2xf64]) jump(p0,i2,v3[2xf64]) """ - vopt = self.vectorize(self.parse_loop(ops),1) - self.assert_equal(vopt.loop, self.parse_loop(opt,add_label=False)) + loop = self.parse_loop(ops) + vopt = self.vectorize(loop,1) + self.assert_equal(loop, self.parse_loop(opt)) def test_variable_expansion(self): ops = """ [p0,i0,f3] - f1 = getarrayitem_raw(p0, i0, descr=floatarraydescr) - f4 = int_add(f1, f3) + f1 = getarrayitem_raw_f(p0, i0, descr=floatarraydescr) + f4 = float_add(f1, f3) i3 = int_add(i0,1) i5 = int_lt(i3, 10) guard_true(i5) [p0, i0] @@ -1056,7 +1061,6 @@ """ opt=""" [p0,i0,f3] - label(p0,i0,f3) v3[2xf64] = vec_expand_f(f3) label(p0,i0,f3,v3[2xf64]) i20 = int_add(i0, 1) @@ -1065,18 +1069,19 @@ i3 = int_lt(i2, 10) guard_true(i3) [p0,i0,f3] i4 = int_add(i0, 2) - i5 = int_lt(i2, 10) - v1[2xf64] = vec_getarrayitem_raw(p0, i0, descr=floatarraydescr) - v2[2xf64] = vec_int_add(v1[2xf64], v3[2xf64]) + i5 = int_lt(i4, 10) + v1[2xf64] = vec_getarrayitem_raw_f(p0, i0, descr=floatarraydescr) + v2[2xf64] = vec_float_add(v1[2xf64], v3[2xf64]) jump(p0,i2,f3,v3[2xf64]) """ - vopt = self.vectorize(self.parse_loop(ops),1) - self.assert_equal(vopt.loop, self.parse_loop(opt, add_label=False)) + loop = self.parse_loop(ops) + vopt = self.vectorize(loop,1) + self.assert_equal(loop, self.parse_loop(opt)) def test_accumulate_basic(self): trace = """ [p0, i0, f0] - f1 = raw_load(p0, i0, descr=floatarraydescr) + f1 = raw_load_f(p0, i0, descr=floatarraydescr) f2 = float_add(f0, f1) i1 = int_add(i0, 8) i2 = int_lt(i1, 100) @@ -1084,28 +1089,31 @@ jump(p0, i1, f2) """ trace_opt = """ - [p0, i0, v2[f64|2]] + [p0, i0, f0] + v6[0xf64] = vec_f() + v7[2xf64] = vec_int_xor(v6[0xf64], v6[0xf64]) + v2[2xf64] = vec_pack_f(v7[2xf64], f0, 0, 1) + label(p0, i0, v2[2xf64]) i1 = int_add(i0, 16) i2 = int_lt(i1, 100) - guard_false(i2) [p0, i0, v[f64|2]] + guard_false(i2) [p0, i0, v2[2xf64]] i10 = int_add(i0, 16) i20 = int_lt(i10, 100) - v1[f64|2] = vec_raw_load(p0, i0, 2, descr=floatarraydescr) - v3[f64|2] = vec_float_add(v2[f64|2], v1[f64|2]) - jump(p0, i1, v3[f64|2]) + v1[2xf64] = vec_raw_load_f(p0, i0, descr=floatarraydescr) + v3[2xf64] = vec_float_add(v2[2xf64], v1[2xf64]) + jump(p0, i1, v3[2xf64]) """ - opt = self.vectorize(self.parse_loop(trace)) - assert len(opt.packset.accum_vars) == 1 - assert opt.loop.inputargs[2] in opt.packset.accum_vars - self.debug_print_operations(opt.loop) + loop = self.parse_loop(trace) + opt = self.vectorize(loop) + self.assert_equal(loop, self.parse_loop(trace_opt)) def test_element_f45_in_guard_failargs(self): ops = """ [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] - f45 = raw_load(i21, i44, descr=floatarraydescr) + f45 = raw_load_f(i21, i44, descr=floatarraydescr) guard_not_invalidated() [p38, p12, p9, p14, f45, p39, i37, i44, f35, i40, p42, i43, None, i28, p36, i41] i46 = int_add(i44, 8) - f47 = raw_load(i4, i41, descr=floatarraydescr) + f47 = raw_load_f(i4, i41, descr=floatarraydescr) i48 = int_add(i41, 8) f49 = float_add(f45, f47) raw_store(i0, i37, f49, descr=floatarraydescr) @@ -1131,8 +1139,8 @@ i55 = int_add(i44, 16) i629 = int_add(i28, 2) i57 = int_ge(i637, i18) - v61 = vec_raw_load(i21, i44, 2, descr=floatarraydescr) - v62 = vec_raw_load(i4, i41, 2, descr=floatarraydescr) + v61 = vec_raw_load_f(i21, i44, 2, descr=floatarraydescr) + v62 = vec_raw_load_f(i4, i41, 2, descr=floatarraydescr) v63 = vec_float_add(v61, v62) vec_raw_store(i0, i37, v63, descr=floatarraydescr) f100 = vec_float_unpack(v61, 1, 1) @@ -1145,9 +1153,9 @@ def test_shrink_vector_size(self): ops = """ [p0,p1,i1] - f1 = getarrayitem_raw(p0, i1, descr=floatarraydescr) + f1 = getarrayitem_raw_f(p0, i1, descr=floatarraydescr) i2 = cast_float_to_singlefloat(f1) - setarrayitem_raw(p1, i1, i2, descr=singlefloatarraydescr) + setarrayitem_raw(p1, i1, i2, descr=float32arraydescr) i3 = int_add(i1, 1) i4 = int_ge(i3, 36) guard_false(i4) [] @@ -1165,29 +1173,30 @@ i6 = int_add(i1, 3) i11 = int_ge(i6, 36) i7 = int_add(i1, 4) - i14 = int_ge(i50, 36) - v17 = vec_getarrayitem_raw(p0, i1, 2, descr=floatarraydescr) + i14 = int_ge(i7, 36) + v17 = vec_getarrayitem_raw_f(p0, i1, descr=floatarraydescr) v19 = vec_cast_float_to_singlefloat(v17) - v18 = vec_getarrayitem_raw(p0, i5, 2, descr=floatarraydescr) + v18 = vec_getarrayitem_raw_f(p0, i5, descr=floatarraydescr) v20 = vec_cast_float_to_singlefloat(v18) - v21 = vec_float_pack(v19, v20, 2, 2) - vec_setarrayitem_raw(p1, i1, v21, descr=singlefloatarraydescr) + v21 = vec_pack_i(v19, v20, 2, 2) + vec_setarrayitem_raw(p1, i1, v21, descr=float32arraydescr) jump(p0, p1, i50) """ - vopt = self.vectorize(self.parse_loop(ops)) - self.assert_equal(vopt.loop, self.parse_loop(opt)) + loop = self.parse_loop(ops) + vopt = self.vectorize(loop) + self.assert_equal(loop, self.parse_loop(opt)) def test_castup_arith_castdown(self): ops = """ [p0,p1,p2,i0,i4] - i10 = raw_load(p0, i0, descr=singlefloatarraydescr) + i10 = raw_load_i(p0, i0, descr=float32arraydescr) i1 = int_add(i0, 4) - i11 = raw_load(p1, i1, descr=singlefloatarraydescr) + i11 = raw_load_i(p1, i1, descr=float32arraydescr) f1 = cast_singlefloat_to_float(i10) f2 = cast_singlefloat_to_float(i11) f3 = float_add(f1, f2) i12 = cast_float_to_singlefloat(f3) - raw_store(p2, i4, i12, descr=singlefloatarraydescr) + raw_store(p2, i4, i12, descr=float32arraydescr) i5 = int_add(i4, 4) i186 = int_lt(i5, 100) guard_true(i186) [] @@ -1209,12 +1218,12 @@ i196 = int_add(i4, 12) i197 = int_lt(i196, 100) i205 = int_add(i4, 16) - i206 = int_lt(i500, 100) - v228 = vec_raw_load(p0, i0, 4, descr=singlefloatarraydescr) + i206 = int_lt(i205, 100) + v228 = vec_raw_load_i(p0, i0, 4, descr=float32arraydescr) v229 = vec_cast_singlefloat_to_float(v228) v230 = vec_int_unpack(v228, 2, 2) v231 = vec_cast_singlefloat_to_float(v230) - v232 = vec_raw_load(p1, i1, 4, descr=singlefloatarraydescr) + v232 = vec_raw_load_i(p1, i1, 4, descr=float32arraydescr) v233 = vec_cast_singlefloat_to_float(v232) v234 = vec_int_unpack(v232, 2, 2) v235 = vec_cast_singlefloat_to_float(v234) @@ -1222,8 +1231,8 @@ v239 = vec_cast_float_to_singlefloat(v237) v236 = vec_float_add(v229, v233) v238 = vec_cast_float_to_singlefloat(v236) - v240 = vec_float_pack(v238, v239, 2, 2) - vec_raw_store(p2, i4, v240, descr=singlefloatarraydescr) + v240 = vec_pack_f(v238, v239, 2, 2) + vec_raw_store(p2, i4, v240, descr=float32arraydescr) jump(p0, p1, p2, i207, i500) """ vopt = self.vectorize(self.parse_loop(ops)) @@ -1280,16 +1289,16 @@ def test_cast_1(self): trace = """ [i9, i10, p2, p11, i12, i13, p4, p5, p14, i15, p8, i16, p17, i18, i19, i20, i21, i22, i23] - i24 = raw_load(i20, i16, descr=singlefloatarraydescr) + i24 = raw_load_i(i20, i16, descr=float32arraydescr) guard_not_invalidated() [p8, p5, p4, p2, i24, p17, i13, i12, i10, i19, p14, p11, i18, i15, i16, None] i27 = int_add(i16, 4) - i28 = raw_load(i21, i19, descr=singlefloatarraydescr) + i28 = raw_load_i(i21, i19, descr=float32arraydescr) i30 = int_add(i19, 4) f31 = cast_singlefloat_to_float(i24) f32 = cast_singlefloat_to_float(i28) f33 = float_add(f31, f32) i34 = cast_float_to_singlefloat(f33) - raw_store(i22, i13, i34, descr=singlefloatarraydescr) + raw_store(i22, i13, i34, descr=float32arraydescr) i36 = int_add(i12, 1) i38 = int_add(i13, 4) i39 = int_ge(i36, i23) @@ -1302,7 +1311,7 @@ def test_all_guard(self): trace = """ [p0, p3, i4, i5, i6, i7] - f8 = raw_load(i6, i5, descr=floatarraydescr) + f8 = raw_load_f(i6, i5, descr=floatarraydescr) guard_not_invalidated() [p0, f8, p3, i5, i4] i9 = cast_float_to_int(f8) i11 = int_and(i9, 255) @@ -1313,13 +1322,14 @@ guard_false(i16) [p0, i13, i15, p3, None, None] jump(p0, p3, i13, i15, i6, i7) """ - opt = self.vectorize(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) + loop = self.parse_loop(trace) + opt = self.vectorize(loop) + self.debug_print_operations(loop) def test_max(self): trace = """ [p3, i4, p2, i5, f6, i7, i8] - f9 = raw_load(i7, i5, descr=floatarraydescr) + f9 = raw_load_f(i7, i5, descr=floatarraydescr) guard_not_invalidated() [p2, f9, f6, i4, i5, p3] i10 = float_ge(f6, f9) guard_false(i10) [p2, f9, f6, None, i4, i5, p3] @@ -1331,173 +1341,9 @@ guard_false(i17) [p2, i16, f9, i14, None, None, None, p3] jump(p3, i14, p2, i16, f9, i7, i8) """ - opt = self.schedule(self.parse_loop(trace), with_guard_opt=True) - self.debug_print_operations(opt.loop) - - - def test_abc(self): - trace=""" - [p0, p1, p5, p6, p7, p12, p13, i14, i15, i16, i17, i18, i19, i20] - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #117 LOAD_NAME') - guard_not_invalidated(descr=) [p1, p0, p5, p6, p7, p12, p13] - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #120 LOAD_CONST') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #123 COMPARE_OP') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #126 POP_JUMP_IF_FALSE') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #129 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #132 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #135 BINARY_SUBSCR') - i23 = int_lt(i14, i15) - guard_true(i23, descr=) [p1, p0, i14, p5, p6, p7, p12, p13, None] - f25 = getarrayitem_raw(i16, i14, descr=floatarraydescr) - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #136 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #139 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #142 BINARY_SUBSCR') - i26 = int_lt(i14, i17) - guard_true(i26, descr=) [p1, p0, i14, p5, p6, p7, p12, p13, f25, None] - f27 = getarrayitem_raw(i18, i14, descr=floatarraydescr) - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #143 BINARY_ADD') - f28 = float_add(f25, f27) - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #144 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #147 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #150 STORE_SUBSCR') - i29 = int_lt(i14, i19) - guard_true(i29, descr=) [p1, p0, i14, p5, p6, p7, p12, p13, f28, None, None] - setarrayitem_raw(i20, i14, f28, descr=floatarraydescr) - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #151 LOAD_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #154 LOAD_CONST') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #157 INPLACE_ADD') - i31 = int_add(i14, 1) - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #158 STORE_NAME') - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #161 JUMP_ABSOLUTE') - i33 = getfield_raw(140489852409120, descr=) - setfield_gc(1234, i31, descr=) - i36 = int_lt(i33, 0) - guard_false(i36, descr=) [p1, p0, p5, p6, p7, p12, p13, None, None, None] - debug_merge_point(0, 0, '. file '/home/rich/proj/da/thesis/bench/user1.py'. line 2> #117 LOAD_NAME') - i22 = int_lt(i14, 2024) - guard_true(i22, descr=) [p1, p0, p5, p6, p7, p12, p13, i14] - jump(p0, p1, p5, p6, p7, p12, p13, i31, i15, i16, i17, i18, i19, i20) - """ - opt = self.vectorize(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) - - def test_bug1(self): - trace=""" - [p0, p1, p6, p7, p11, i83, f57, f61, f65, f70, f78, f81, i48, i56, p46] - guard_not_invalidated(descr=) [p1, p0, p6, p7, p11, f81, f78, f70, f65, f61, f57, i83] - i91 = int_lt(i83, i48) - guard_true(i91, descr=) [p1, p0, p6, p7, p11, i48, f81, f78, f70, f65, f61, f57, i83] - f92 = getarrayitem_raw(i56, i83, descr=floatarraydescr) - i93 = int_add(i83, 1) - i94 = int_lt(i93, i48) - guard_true(i94, descr=) [p1, p0, p46, i93, p6, p7, p11, f92, None, f81, f78, f70, f65, f61, None, i83] - f95 = getarrayitem_raw(i56, i93, descr=floatarraydescr) - i96 = int_add(i83, 2) - i97 = int_lt(i96, i48) - guard_true(i97, descr=) [p1, p0, p46, i96, p6, p7, p11, f95, f92, None, f81, f78, f70, f65, None, None, i83] - f98 = getarrayitem_raw(i56, i96, descr=floatarraydescr) - f99 = float_sub(f98, 128.000000) - f100 = float_mul(1.370705, f99) - f101 = float_add(f92, f100) - f102 = float_mul(0.698001, f99) - f103 = float_sub(f92, f102) - f104 = float_sub(f95, 128.000000) - f105 = float_mul(0.337633, f104) - f106 = float_sub(f103, f105) - f107 = float_mul(1.732446, f104) - f108 = float_add(f92, f107) - i109 = int_add(i83, 3) - i110 = getfield_raw(140340519358368, descr=) - i111 = int_lt(i110, 0) - guard_false(i111, descr=) [p1, p0, p6, p7, p11, f108, f106, f101, f98, i109, f95, f92, None, None, None, None, None, None, None, None] - jump(p0, p1, p6, p7, p11, i109, f92, f95, f98, f101, f106, f108, i48, i56, p46) - """ - opt = self.schedule(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) - - def test_1(self): - trace = """ - [p0, p1, p6, p7, i13, p14, p15] - guard_not_invalidated(descr=) [p1, p0, p6, p7, i13] - i17 = int_lt(i13, 10000) - guard_true(i17, descr=) [p1, p0, p6, p7, i13] - i18 = getfield_gc(p14, descr=) - i19 = uint_ge(i13, i18) - guard_false(i19, descr=) [p1, p0, i18, i13, p14, p6, p7, None] - p21 = getfield_gc(p14, descr=) - f22 = getarrayitem_gc(p21, i13, descr=) - i23 = getfield_gc(p15, descr=) - i24 = uint_ge(i13, i23) - guard_false(i24, descr=) [p1, p0, i23, i13, p15, p6, p7, f22, None] - p25 = getfield_gc(p15, descr=) - f26 = getarrayitem_gc(p25, i13, descr=floatarraydescr) - f27 = float_add(f22, f26) - setarrayitem_gc(p21, i13, f27, descr=floatarraydescr) - i29 = int_add(i13, 1) - #i31 = getfield_raw(140229696280448, descr=) - i33 = int_lt(0, 1) - guard_false(i33, descr=) [p1, p0, p6, p7, i29, None, None] - jump(p0, p1, p6, p7, i29, p14, p15) - """ - trace = """ - [p0, p1, p6, p7, p8, p11, p13, p15, i46, f43, i32, i36, i40] - i51 = int_lt(i46, i32) - guard_true(i51, descr=) [p1, p0, p15, p6, p7, p8, p11, p13, f43, i46] - i52 = int_lt(i46, i36) - guard_true(i52, descr=) [p1, p0, p11, i46, p6, p7, p8, p13, p15, f43, None] - f54 = getarrayitem_raw(i40, i46, descr=floatarraydescr) - f55 = float_add(f43, f54) - i56 = int_add(i46, 1) - jump(p0, p1, p6, p7, p8, p11, p13, p15, i56, f55, i32, i36, i40) - """ - opt = self.schedule(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) - - def test_arraylen(self): - trace = """ - [i45, i33, p40] - # while i < len(l): - # LOAD_FAST i - # LOAD_GLOBAL len - guard_not_invalidated(descr=) [i33,p40] - # LOAD_FAST l - # CALL_FUNCTION 1 - # COMPARE_OP < - i50 = int_lt(i45, i33) - guard_true(i50) [i50,i33,p40] - # POP_JUMP_IF_FALSE 70 - # l[i] = l[i] + 1 - # LOAD_FAST l - # LOAD_FAST i - # BINARY_SUBSCR - i51 = uint_ge(i45, i33) - guard_false(i51) [i50, i45] - i52 = getarrayitem_gc(p40, i45, descr=arraydescr) - # LOAD_CONST 1 - # BINARY_ADD - i53 = int_add(i52, 1) - #guard_no_overflow(descr=) [] - # LOAD_FAST l - # LOAD_FAST i - # STORE_SUBSCR - setarrayitem_gc(p40, i45, i53, descr=arraydescr) - # i += 1 - # LOAD_FAST i - # LOAD_CONST 1 - # INPLACE_ADD - i54 = int_add(i45,1) - # STORE_FAST i - # JUMP_ABSOLUTE 21 - #getfield_raw_i(140199654614400, descr=) - #None = i55 < 0 - #guard(i56 is false) - # LOAD_FAST i - #i34 = arraylen_gc(p40, descr=) - jump(i54, i33, p40) - """ - opt = self.vectorize(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) - + loop = self.parse_loop(trace) + opt = self.schedule(loop, with_guard_opt=True) + self.debug_print_operations(loop) class TestLLtype(BaseTestVectorize, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -363,7 +363,7 @@ pack_count = self.packset.pack_count() def follow_use_defs(self, pack): - assert isinstance(pack, Pair) + assert pack.numops() == 2 for ldep in pack.leftmost(True).depends(): for rdep in pack.rightmost(True).depends(): lnode = ldep.to @@ -380,7 +380,7 @@ self.packset.add_pack(pair) def follow_def_uses(self, pack): - assert isinstance(pack, Pair) + assert pack.numops() == 2 print "lprov", pack.leftmost(node=True).provides_count(), print "rprov", pack.rightmost(node=True).provides_count() for ldep in pack.leftmost(node=True).provides(): @@ -510,6 +510,7 @@ earlyexit = graph.imaginary_node("early exit") guards = graph.guards one_valid = False + valid_guards = [] for guard_node in guards: modify_later = [] last_prev_node = None @@ -541,13 +542,16 @@ # every edge that starts in the guard, the early exit # inherts the edge and guard then provides to early exit for dep in guard_node.provides()[:]: - earlyexit.edge_to(dep.target_node()) + assert not dep.target_node().is_imaginary() + earlyexit.edge_to(dep.target_node(), failarg=True) guard_node.remove_edge_to(dep.target_node()) + valid_guards.append(guard_node) + guard_node.edge_to(earlyexit) - - for node in zero_deps.keys(): - earlyexit.edge_to(node) self.mark_guard(guard_node, loop) + for node in zero_deps.keys(): + assert not node.is_imaginary() + earlyexit.edge_to(node) if one_valid: return graph return None @@ -770,7 +774,7 @@ # considered. => tree pattern matching problem. return None operator = AccumPack.SUPPORTED[opnum] - return AccumPack(lnode, rnode, operator, scalar, index) + return AccumPack([lnode, rnode], operator, scalar, index) return None @@ -785,34 +789,34 @@ for pack in self.packs: if not pack.is_accumulating(): continue - accum = pack.accum - datatype = accum.getdatatype() - bytesize = accum.getbytesize() + assert isinstance(pack, AccumPack) + datatype = pack.getdatatype() + bytesize = pack.getbytesize() count = vec_reg_size // bytesize signed = datatype == 'i' oplist = state.invariant_oplist # reset the box to zeros or ones - if accum.operator == Accum.PLUS: + if pack.reduce_init() == 0: vecop = OpHelpers.create_vec(datatype, bytesize, signed) oplist.append(vecop) vecop = VecOperation(rop.VEC_INT_XOR, [vecop, vecop], vecop, count) oplist.append(vecop) - elif accum.operator == Accum.MULTIPLY: + elif pack.reduce_init() == 1: # multiply is only supported by floats vecop = OpHelpers.create_vec_expand(ConstFloat(1.0), bytesize, signed, count) oplist.append(vecop) else: - raise NotImplementedError("cannot handle %s" % accum.operator) + raise NotImplementedError("cannot handle %s" % pack.operator) # pack the scalar value - args = [vecop, accum.getseed(), ConstInt(0), ConstInt(1)] + args = [vecop, pack.getseed(), ConstInt(0), ConstInt(1)] vecop = OpHelpers.create_vec_pack(datatype, args, bytesize, signed, count) oplist.append(vecop) # rename the variable with the box - state.setvector_of_box(accum.getseed(), 0, vecop) # prevent it from expansion - state.renamer.start_renaming(accum.getseed(), vecop) + state.setvector_of_box(pack.getseed(), 0, vecop) # prevent it from expansion + state.renamer.start_renaming(pack.getseed(), vecop) def split_overloaded_packs(self): newpacks = [] diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -308,6 +308,8 @@ if arg == 'None': fail_arg = None else: + if arg.startswith('v') and '[' in arg: + arg = arg[:arg.find('[')] try: fail_arg = self.vars[arg] except KeyError: From noreply at buildbot.pypy.org Fri Sep 18 16:52:55 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 16:52:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip this test if the address happens not to fit in 32 bits Message-ID: <20150918145255.BECCE1C0933@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79688:bc98bea0ea47 Date: 2015-09-18 16:52 +0200 http://bitbucket.org/pypy/pypy/changeset/bc98bea0ea47/ Log: Skip this test if the address happens not to fit in 32 bits diff --git a/rpython/jit/backend/x86/test/test_regloc.py b/rpython/jit/backend/x86/test/test_regloc.py --- a/rpython/jit/backend/x86/test/test_regloc.py +++ b/rpython/jit/backend/x86/test/test_regloc.py @@ -1,5 +1,5 @@ import struct, sys -from rpython.jit.backend.x86.rx86 import R +from rpython.jit.backend.x86.rx86 import R, fits_in_32bits from rpython.jit.backend.x86.regloc import * from rpython.jit.backend.x86.test.test_rx86 import CodeBuilder32, CodeBuilder64, assert_encodes_as from rpython.jit.backend.x86.assembler import heap @@ -112,6 +112,9 @@ def test_follow_jump_instructions_32(): buf = lltype.malloc(rffi.CCHARP.TO, 80, flavor='raw') raw = rffi.cast(lltype.Signed, buf) + if not fits_in_32bits(raw): + lltype.free(buf, flavor='raw') + py.test.skip("not testable") mc = Fake32CodeBlockWrapper(); mc.WORD = 4; mc.relocations = [] mc.RET() mc.copy_to_raw_memory(raw) From noreply at buildbot.pypy.org Fri Sep 18 17:14:51 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 17:14:51 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit fix Message-ID: <20150918151451.10AAC1C1C68@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79689:59f91f4b5f82 Date: 2015-09-18 17:14 +0200 http://bitbucket.org/pypy/pypy/changeset/59f91f4b5f82/ Log: 32-bit fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2293,6 +2293,7 @@ func_ptr = llhelper(lltype.Ptr(FUNC), func_void) calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) + gfs = longlong.getfloatstorage for (operation, arg1, arg2_if_true, arg2_if_false) in [ ('int_lt', -5, 2, -5), @@ -2303,8 +2304,8 @@ ('int_xor', 7, 3, 7), # test without a comparison at all ('int_is_true', 4242, 1, 0), ('int_is_zero', 4242, 0, 1), - ('float_lt', -0.5, 0.2, -0.5), - ('float_eq', 1.1, 1.1, 1.2), + ('float_lt', gfs(-0.5), gfs(0.2), gfs(-0.5)), + ('float_eq', gfs(1.1), gfs(1.1), gfs(1.2)), ]: called = [] From noreply at buildbot.pypy.org Fri Sep 18 17:20:20 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 17:20:20 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit fixes Message-ID: <20150918152020.79C851C1F5A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79690:6d09c895938b Date: 2015-09-18 17:19 +0200 http://bitbucket.org/pypy/pypy/changeset/6d09c895938b/ Log: 32-bit fixes diff --git a/rpython/jit/backend/test/calling_convention_test.py b/rpython/jit/backend/test/calling_convention_test.py --- a/rpython/jit/backend/test/calling_convention_test.py +++ b/rpython/jit/backend/test/calling_convention_test.py @@ -152,6 +152,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) + res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001 def test_call_aligned_with_args_on_the_stack(self): @@ -194,6 +195,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) + res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001 def test_call_alignment_call_assembler(self): From noreply at buildbot.pypy.org Fri Sep 18 17:33:18 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 17:33:18 +0200 (CEST) Subject: [pypy-commit] pypy default: Silence warnings Message-ID: <20150918153318.49C0C1C1F97@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79691:2e5394a3ed87 Date: 2015-09-18 17:28 +0200 http://bitbucket.org/pypy/pypy/changeset/2e5394a3ed87/ Log: Silence warnings diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -80,8 +80,8 @@ self.gc_size_of_header = gc_ll_descr.gcheaderbuilder.size_gc_header else: self.gc_size_of_header = WORD # for tests - self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn) - self.memset_addr = self.cpu.cast_ptr_to_int(memset_fn) + self.memcpy_addr = rffi.cast(lltype.Signed, memcpy_fn) + self.memset_addr = rffi.cast(lltype.Signed, memset_fn) self._build_failure_recovery(False, withfloats=False) self._build_failure_recovery(True, withfloats=False) self._build_wb_slowpath(False) diff --git a/rpython/jit/backend/llsupport/codemap.py b/rpython/jit/backend/llsupport/codemap.py --- a/rpython/jit/backend/llsupport/codemap.py +++ b/rpython/jit/backend/llsupport/codemap.py @@ -15,7 +15,7 @@ from rpython.rlib.entrypoint import jit_entrypoint from rpython.rlib.rbisect import bisect_right, bisect_right_addr from rpython.rlib.rbisect import bisect_left, bisect_left_addr -from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.translator import cdir @@ -74,11 +74,12 @@ stack_depth_at_loc = llexternal('pypy_jit_stack_depth_at_loc', [lltype.Signed], lltype.Signed) find_codemap_at_addr = llexternal('pypy_find_codemap_at_addr', - [lltype.Signed, rffi.CArrayPtr(lltype.Signed)], lltype.Signed) + [lltype.Signed, rffi.CArrayPtr(lltype.Signed)], + llmemory.Address) yield_bytecode_at_addr = llexternal('pypy_yield_codemap_at_addr', - [lltype.Signed, lltype.Signed, + [llmemory.Address, lltype.Signed, rffi.CArrayPtr(lltype.Signed)], - lltype.Signed) + lltype.Signed) class CodemapStorage(object): From noreply at buildbot.pypy.org Fri Sep 18 17:45:04 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 17:45:04 +0200 (CEST) Subject: [pypy-commit] pypy default: Extra op, killed by the backend anyway Message-ID: <20150918154504.C32E61C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79692:c689e7bd9ef6 Date: 2015-09-18 17:44 +0200 http://bitbucket.org/pypy/pypy/changeset/c689e7bd9ef6/ Log: Extra op, killed by the backend anyway diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -148,6 +148,7 @@ i18 = force_token() setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>) guard_not_invalidated(descr=...) + i84 = int_sub(i14, 1) i21 = int_lt(i10, 0) guard_false(i21, descr=...) i22 = int_lt(i10, i14) From noreply at buildbot.pypy.org Fri Sep 18 17:48:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 17:48:10 +0200 (CEST) Subject: [pypy-commit] pypy default: more of the same Message-ID: <20150918154810.BD3511C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79693:66eccb74f01b Date: 2015-09-18 16:51 +0100 http://bitbucket.org/pypy/pypy/changeset/66eccb74f01b/ Log: more of the same diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -181,6 +181,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i88 = int_sub(i9, 1) i25 = int_ge(i11, i9) guard_false(i25, descr=...) i27 = int_add_ovf(i7, i11) @@ -213,6 +214,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i95 = int_sub(i9, 1) i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) From noreply at buildbot.pypy.org Fri Sep 18 18:07:07 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 18:07:07 +0200 (CEST) Subject: [pypy-commit] pypy default: fix on 32-bit Message-ID: <20150918160707.662041C13AF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79694:d4c467d8b229 Date: 2015-09-18 18:07 +0200 http://bitbucket.org/pypy/pypy/changeset/d4c467d8b229/ Log: fix on 32-bit diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -238,7 +238,7 @@ # replace "x / const" by "x * (1/const)" if possible newop = op if v2.is_constant(): - divisor = v2.getfloatstorage() + divisor = v2.getfloat() fraction = math.frexp(divisor)[0] # This optimization is valid for powers of two # but not for zeroes, some denormals and NaN: From noreply at buildbot.pypy.org Fri Sep 18 18:09:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 18:09:48 +0200 (CEST) Subject: [pypy-commit] pypy default: more of the same Message-ID: <20150918160948.744BB1C0148@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79695:c1aa791eca45 Date: 2015-09-18 18:10 +0200 http://bitbucket.org/pypy/pypy/changeset/c1aa791eca45/ Log: more of the same diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -220,10 +220,10 @@ v2 = self.get_box_replacement(rhs) if v1.is_constant(): - if v1.getfloatstorage() == 1.0: + if v1.getfloat() == 1.0: self.make_equal_to(op, v2) return - elif v1.getfloatstorage() == -1.0: + elif v1.getfloat() == -1.0: newop = self.replace_op_with(op, rop.FLOAT_NEG, args=[rhs]) self.emit_operation(newop) return From noreply at buildbot.pypy.org Fri Sep 18 19:33:32 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 19:33:32 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for a corner case: functions returning a constant 'nan' Message-ID: <20150918173332.6FF821C1F5A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79696:071d445c8497 Date: 2015-09-18 19:33 +0200 http://bitbucket.org/pypy/pypy/changeset/071d445c8497/ Log: Fix for a corner case: functions returning a constant 'nan' diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py --- a/rpython/rtyper/rtyper.py +++ b/rpython/rtyper/rtyper.py @@ -13,7 +13,7 @@ import os -import py +import py, math from rpython.annotator import model as annmodel, unaryop, binaryop from rpython.rtyper.llannotation import SomePtr, lltype_to_annotation @@ -446,7 +446,11 @@ if isinstance(resultvar, Constant) and \ isinstance(hop.r_result.lowleveltype, Primitive) and \ hop.r_result.lowleveltype is not Void: - assert resultvar.value == hop.s_result.const + # assert that they are equal, or both are 'nan' + assert resultvar.value == hop.s_result.const or ( + math.isnan(resultvar.value) and + math.isnan(hop.s_result.const)) + resulttype = resultvar.concretetype op.result.concretetype = hop.r_result.lowleveltype if op.result.concretetype != resulttype: From noreply at buildbot.pypy.org Fri Sep 18 19:38:44 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 19:38:44 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip this part of the test on 32-bit Message-ID: <20150918173844.9E37A1C1F5A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79697:9f766aaa5b89 Date: 2015-09-18 19:39 +0200 http://bitbucket.org/pypy/pypy/changeset/9f766aaa5b89/ Log: Skip this part of the test on 32-bit diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py --- a/rpython/jit/metainterp/test/test_resume.py +++ b/rpython/jit/metainterp/test/test_resume.py @@ -1465,10 +1465,12 @@ assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 # - py.test.raises(TagOverflow, modifier._add_pending_fields, FakeOptimizer(), - [ResOperation(rop.SETARRAYITEM_GC, - [a42, ConstInt(2147483648), a63], - descr=array_a)]) + if sys.maxint >= 2147483648: + py.test.raises(TagOverflow, modifier._add_pending_fields, + FakeOptimizer(), + [ResOperation(rop.SETARRAYITEM_GC, + [a42, ConstInt(2147483648), a63], + descr=array_a)]) def test_resume_reader_fields_and_arrayitems(): class ResumeReader(AbstractResumeDataReader): From noreply at buildbot.pypy.org Fri Sep 18 21:09:57 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 21:09:57 +0200 (CEST) Subject: [pypy-commit] pypy default: Randomly attempting to fix arm by copying the Jit386Mixin from Message-ID: <20150918190957.92AAB1C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79698:e02c3c4e998f Date: 2015-09-18 21:10 +0200 http://bitbucket.org/pypy/pypy/changeset/e02c3c4e998f/ Log: Randomly attempting to fix arm by copying the Jit386Mixin from x86/test/test_basic diff --git a/rpython/jit/backend/arm/test/support.py b/rpython/jit/backend/arm/test/support.py --- a/rpython/jit/backend/arm/test/support.py +++ b/rpython/jit/backend/arm/test/support.py @@ -10,7 +10,9 @@ class JitARMMixin(support.LLJitMixin): type_system = 'lltype' CPUClass = getcpuclass() - basic = True + # we have to disable unroll + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + basic = False def check_jumps(self, maxcount): pass From noreply at buildbot.pypy.org Fri Sep 18 21:13:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 21:13:50 +0200 (CEST) Subject: [pypy-commit] pypy default: fix? Message-ID: <20150918191350.28AAB1C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79699:bb607daa5d7a Date: 2015-09-18 21:13 +0200 http://bitbucket.org/pypy/pypy/changeset/bb607daa5d7a/ Log: fix? diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py --- a/rpython/jit/backend/arm/test/test_regalloc.py +++ b/rpython/jit/backend/arm/test/test_regalloc.py @@ -215,14 +215,14 @@ def test_exception_bridge_no_exception(self): ops = ''' [i0] - i1 = same_as(1) - call(ConstClass(raising_fptr), i0, descr=raising_calldescr) + i1 = same_as_i(1) + call_n(ConstClass(raising_fptr), i0, descr=raising_calldescr) guard_exception(ConstClass(zero_division_error)) [i1] finish(0) ''' bridge_ops = ''' [i3] - i2 = same_as(2) + i2 = same_as_i(2) guard_no_exception() [i2] finish(1) ''' @@ -379,7 +379,7 @@ def test_bug_wrong_stack_adj(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - i9 = same_as(0) + i9 = same_as_i(0) guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -387,7 +387,7 @@ assert self.getint(0) == 0 bridge_ops = ''' [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] - call(ConstClass(raising_fptr), 0, descr=raising_calldescr) + call_n(ConstClass(raising_fptr), 0, descr=raising_calldescr) guard_true(i0) [i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -430,7 +430,7 @@ def test_cmp_op_0(self): ops = ''' [i0, i3] - i1 = same_as(1) + i1 = same_as_i(1) i2 = int_lt(i0, 100) guard_true(i3) [i1, i2] finish(i2) @@ -630,7 +630,7 @@ def test_one_call(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_true(i10), [i10, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -639,8 +639,8 @@ def test_two_calls(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) - i11 = call(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) + i11 = call_i(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) guard_true(i11) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -649,7 +649,7 @@ def test_call_many_arguments(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] - i8 = call(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) + i8 = call_i(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) finish(i8) ''' self.interpret(ops, [2, 3, 4, 5, 6, 7, 8, 9]) @@ -658,7 +658,7 @@ def test_bridge_calls_1(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i2 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_value(i2, 0, descr=fdescr1) [i2, i1] finish(i1) ''' @@ -666,7 +666,7 @@ assert self.getint(0) == 5 ops = ''' [i2, i1] - i3 = call(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) + i3 = call_i(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -677,7 +677,7 @@ def test_bridge_calls_2(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) + i2 = call_i(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) guard_value(i2, 0, descr=fdescr1) [i2] finish(i1) ''' @@ -685,7 +685,7 @@ assert self.getint(0) == 4 * 7 ops = ''' [i2] - i3 = call(ConstClass(f1ptr), i2, descr=f1_calldescr) + i3 = call_i(ConstClass(f1ptr), i2, descr=f1_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -734,7 +734,7 @@ loop2 = """ [i0] i1 = force_token() - i2 = call_assembler(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) + i2 = call_assembler_i(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) guard_not_forced() [i0] guard_false(i0) [i0, i2] """ @@ -749,23 +749,23 @@ label(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) i11 = int_add(i0, 1) i12 = int_lt(i11, 2) - i13 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i14 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i15 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i16 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i17 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i18 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i19 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i20 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i21 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i22 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i23 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i24 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i26 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i27 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i28 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i29 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i30 = call(ConstClass(f_fptr), i12, descr=f_calldescr) + i13 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i14 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i15 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i16 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i17 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i18 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i19 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i20 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i21 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i22 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i23 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i24 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i26 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i27 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i28 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i29 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i30 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) guard_true(i12) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] jump(i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) """ From noreply at buildbot.pypy.org Fri Sep 18 21:13:52 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 21:13:52 +0200 (CEST) Subject: [pypy-commit] pypy default: Kill this old-style test Message-ID: <20150918191352.62D251C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79700:e2d673030e01 Date: 2015-09-18 21:14 +0200 http://bitbucket.org/pypy/pypy/changeset/e2d673030e01/ Log: Kill this old-style test diff --git a/rpython/jit/backend/arm/test/test_regalloc2.py b/rpython/jit/backend/arm/test/test_regalloc2.py deleted file mode 100644 --- a/rpython/jit/backend/arm/test/test_regalloc2.py +++ /dev/null @@ -1,281 +0,0 @@ -import py -from rpython.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, BasicFailDescr, BasicFinalDescr -from rpython.jit.metainterp.history import JitCellToken -from rpython.jit.metainterp.resoperation import rop -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.backend.arm.arch import WORD -CPU = getcpuclass() - -def test_bug_rshift(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_ADD, [v1, v1], v2), - ResOperation(rop.INT_INVERT, [v2], v3), - ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(1)), - ] - operations[-2].setfailargs([v4, v3]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, 9) - assert cpu.get_int_value(deadframe, 0) == (9 >> 3) - assert cpu.get_int_value(deadframe, 1) == (~18) - -def test_bug_int_is_true_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - tmp5 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_MUL, [v1, v1], v2), - ResOperation(rop.INT_MUL, [v2, v1], v3), - ResOperation(rop.INT_IS_TRUE, [v2], tmp5), - ResOperation(rop.INT_IS_ZERO, [tmp5], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()), - ] - operations[-2].setfailargs([v4, v3, tmp5]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, -10) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == -1000 - assert cpu.get_int_value(deadframe, 2) == 1 - -def test_bug_0(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - tmp46 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_GT, [v3, ConstInt(-48)], v11), - ResOperation(rop.INT_XOR, [v8, v1], v12), - ResOperation(rop.INT_GT, [v6, ConstInt(-9)], v13), - ResOperation(rop.INT_LE, [v13, v2], v14), - ResOperation(rop.INT_LE, [v11, v5], v15), - ResOperation(rop.UINT_GE, [v13, v13], v16), - ResOperation(rop.INT_OR, [v9, ConstInt(-23)], v17), - ResOperation(rop.INT_LT, [v10, v13], v18), - ResOperation(rop.INT_OR, [v15, v5], v19), - ResOperation(rop.INT_XOR, [v17, ConstInt(54)], v20), - ResOperation(rop.INT_MUL, [v8, v10], v21), - ResOperation(rop.INT_OR, [v3, v9], v22), - ResOperation(rop.INT_AND, [v11, ConstInt(-4)], tmp41), - ResOperation(rop.INT_OR, [tmp41, ConstInt(1)], tmp42), - ResOperation(rop.INT_MOD, [v12, tmp42], v23), - ResOperation(rop.INT_IS_TRUE, [v6], v24), - ResOperation(rop.UINT_RSHIFT, [v15, ConstInt(6)], v25), - ResOperation(rop.INT_OR, [ConstInt(-4), v25], v26), - ResOperation(rop.INT_INVERT, [v8], v27), - ResOperation(rop.INT_SUB, [ConstInt(-113), v11], v28), - ResOperation(rop.INT_NEG, [v7], v29), - ResOperation(rop.INT_NEG, [v24], v30), - ResOperation(rop.INT_FLOORDIV, [v3, ConstInt(53)], v31), - ResOperation(rop.INT_MUL, [v28, v27], v32), - ResOperation(rop.INT_AND, [v18, ConstInt(-4)], tmp43), - ResOperation(rop.INT_OR, [tmp43, ConstInt(1)], tmp44), - ResOperation(rop.INT_MOD, [v26, tmp44], v33), - ResOperation(rop.INT_OR, [v27, v19], v34), - ResOperation(rop.UINT_LT, [v13, ConstInt(1)], v35), - ResOperation(rop.INT_AND, [v21, ConstInt(31)], tmp45), - ResOperation(rop.INT_RSHIFT, [v21, tmp45], v36), - ResOperation(rop.INT_AND, [v20, ConstInt(31)], tmp46), - ResOperation(rop.UINT_RSHIFT, [v4, tmp46], v37), - ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), - ResOperation(rop.INT_NEG, [v7], v39), - ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ] - operations[-1].setfailargs([v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - args = [-13 , 10 , 10 , 8 , -8 , -16 , -18 , 46 , -12 , 26] - deadframe = cpu.execute_token(looptoken, *args) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 0 - assert cpu.get_int_value(deadframe, 2) == 0 - assert cpu.get_int_value(deadframe, 3) == 0 - assert cpu.get_int_value(deadframe, 4) == 1 - assert cpu.get_int_value(deadframe, 5) == -7 - assert cpu.get_int_value(deadframe, 6) == 1 - assert cpu.get_int_value(deadframe, 7) == 0 - assert cpu.get_int_value(deadframe, 8) == -2 - assert cpu.get_int_value(deadframe, 9) == 18 - assert cpu.get_int_value(deadframe, 10) == 1 - assert cpu.get_int_value(deadframe, 11) == 18 - assert cpu.get_int_value(deadframe, 12) == -1 - assert cpu.get_int_value(deadframe, 13) == 0 - -def test_bug_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_LT, [v6, ConstInt(0)], v11), - ResOperation(rop.INT_AND, [v3, ConstInt(31)], tmp41), - ResOperation(rop.INT_RSHIFT, [v3, tmp41], v12), - ResOperation(rop.INT_NEG, [v2], v13), - ResOperation(rop.INT_ADD, [v11, v7], v14), - ResOperation(rop.INT_OR, [v3, v2], v15), - ResOperation(rop.INT_OR, [v12, v12], v16), - ResOperation(rop.INT_NE, [v2, v5], v17), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp42), - ResOperation(rop.UINT_RSHIFT, [v14, tmp42], v18), - ResOperation(rop.INT_AND, [v14, ConstInt(31)], tmp43), - ResOperation(rop.INT_LSHIFT, [ConstInt(7), tmp43], v19), - ResOperation(rop.INT_NEG, [v19], v20), - ResOperation(rop.INT_MOD, [v3, ConstInt(1)], v21), - ResOperation(rop.UINT_GE, [v15, v1], v22), - ResOperation(rop.INT_AND, [v16, ConstInt(31)], tmp44), - ResOperation(rop.INT_LSHIFT, [v8, tmp44], v23), - ResOperation(rop.INT_IS_TRUE, [v17], v24), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp45), - ResOperation(rop.INT_LSHIFT, [v14, tmp45], v25), - ResOperation(rop.INT_LSHIFT, [v5, ConstInt(17)], v26), - ResOperation(rop.INT_EQ, [v9, v15], v27), - ResOperation(rop.INT_GE, [ConstInt(0), v6], v28), - ResOperation(rop.INT_NEG, [v15], v29), - ResOperation(rop.INT_NEG, [v22], v30), - ResOperation(rop.INT_ADD, [v7, v16], v31), - ResOperation(rop.UINT_LT, [v19, v19], v32), - ResOperation(rop.INT_ADD, [v2, ConstInt(1)], v33), - ResOperation(rop.INT_NEG, [v5], v34), - ResOperation(rop.INT_ADD, [v17, v24], v35), - ResOperation(rop.UINT_LT, [ConstInt(2), v16], v36), - ResOperation(rop.INT_NEG, [v9], v37), - ResOperation(rop.INT_GT, [v4, v11], v38), - ResOperation(rop.INT_LT, [v27, v22], v39), - ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ] - operations[-1].setfailargs([v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - args = [17 , -20 , -6 , 6 , 1 , 13 , 13 , 9 , 49 , 8] - deadframe = cpu.execute_token(looptoken, *args) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 8 - assert cpu.get_int_value(deadframe, 2) == 1 - assert cpu.get_int_value(deadframe, 3) == 131072 - assert cpu.get_int_value(deadframe, 4) == 20 - assert cpu.get_int_value(deadframe, 5) == -1 - assert cpu.get_int_value(deadframe, 6) == 0 - assert cpu.get_int_value(deadframe, 7) == -19 - assert cpu.get_int_value(deadframe, 8) == 6 - assert cpu.get_int_value(deadframe, 9) == 26 - assert cpu.get_int_value(deadframe, 10) == 12 - assert cpu.get_int_value(deadframe, 11) == 0 - assert cpu.get_int_value(deadframe, 12) == 0 - assert cpu.get_int_value(deadframe, 13) == 2 - assert cpu.get_int_value(deadframe, 14) == 2 - assert cpu.get_int_value(deadframe, 15) == 1 - assert cpu.get_int_value(deadframe, 16) == -57344 - assert cpu.get_int_value(deadframe, 17) == 1 - assert cpu.get_int_value(deadframe, 18) == -1 - if WORD == 4: - assert cpu.get_int_value(deadframe, 19) == -2147483648 - elif WORD == 8: - assert cpu.get_int_value(deadframe, 19) == 19327352832 - assert cpu.get_int_value(deadframe, 20) == -49 From noreply at buildbot.pypy.org Fri Sep 18 21:19:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 18 Sep 2015 21:19:02 +0200 (CEST) Subject: [pypy-commit] pypy default: fix? Message-ID: <20150918191902.0D83D1C076F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79701:3ee9698ef91b Date: 2015-09-18 21:17 +0200 http://bitbucket.org/pypy/pypy/changeset/3ee9698ef91b/ Log: fix? diff --git a/rpython/jit/backend/arm/test/test_helper.py b/rpython/jit/backend/arm/test/test_helper.py --- a/rpython/jit/backend/arm/test/test_helper.py +++ b/rpython/jit/backend/arm/test/test_helper.py @@ -1,6 +1,8 @@ from rpython.jit.backend.arm.helper.assembler import count_reg_args -from rpython.jit.metainterp.history import (BoxInt, BoxPtr, BoxFloat, - INT, REF, FLOAT) +from rpython.jit.metainterp.history import INT, REF, FLOAT +from rpython.jit.metainterp.resoperation import InputArgInt as BoxInt +from rpython.jit.metainterp.resoperation import InputArgRef as BoxPtr +from rpython.jit.metainterp.resoperation import InputArgFloat as BoxFloat def test_count_reg_args(): From noreply at buildbot.pypy.org Sat Sep 19 09:55:51 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 09:55:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix sandboxing on Windows, at least as far as running the tests Message-ID: <20150919075551.AC5801C11E1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79702:890cecbe0c7d Date: 2015-09-19 09:56 +0200 http://bitbucket.org/pypy/pypy/changeset/890cecbe0c7d/ Log: Fix sandboxing on Windows, at least as far as running the tests diff --git a/rpython/translator/c/src/entrypoint.c b/rpython/translator/c/src/entrypoint.c --- a/rpython/translator/c/src/entrypoint.c +++ b/rpython/translator/c/src/entrypoint.c @@ -27,6 +27,13 @@ # include "forwarddecl.h" # endif +#if defined(MS_WINDOWS) && defined(RPY_SANDBOXED) +# include +# include +# include +#endif + + RPY_EXTERN int pypy_main_function(int argc, char *argv[]) { @@ -34,6 +41,11 @@ int i, exitcode; RPyListOfString *list; +#if defined(MS_WINDOWS) && defined(RPY_SANDBOXED) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + #ifdef PYPY_USE_ASMGCC pypy_g_rpython_rtyper_lltypesystem_rffi_StackCounter.sc_inst_stacks_counter++; #endif diff --git a/rpython/translator/sandbox/rsandbox.py b/rpython/translator/sandbox/rsandbox.py --- a/rpython/translator/sandbox/rsandbox.py +++ b/rpython/translator/sandbox/rsandbox.py @@ -3,10 +3,6 @@ trampolines that marshal their input arguments, dump them to STDOUT, and wait for an answer on STDIN. Enable with 'translate.py --sandbox'. """ -import sys -if sys.platform == 'win32': - raise TypeError("sandbox not supported on windows") - import py from rpython.rlib import rmarshal, types diff --git a/rpython/translator/sandbox/sandlib.py b/rpython/translator/sandbox/sandlib.py --- a/rpython/translator/sandbox/sandlib.py +++ b/rpython/translator/sandbox/sandlib.py @@ -10,6 +10,9 @@ from rpython.translator.sandbox.vfs import UID, GID import py +WIN32 = os.name == "nt" + + def create_log(): """Make and return a log for the sandbox to use, if needed.""" # These imports are local to avoid importing pypy if we don't need to. @@ -40,14 +43,7 @@ RESULTTYPE_STATRESULT = object() RESULTTYPE_LONGLONG = object() -def read_message(f, timeout=None): - # warning: 'timeout' is not really reliable and should only be used - # for testing. Also, it doesn't work if the file f does any buffering. - if timeout is not None: - import select - iwtd, owtd, ewtd = select.select([f], [], [], timeout) - if not iwtd: - raise EOFError("timed out waiting for data") +def read_message(f): return marshal.load(f) def write_message(g, msg, resulttype=None): @@ -140,7 +136,7 @@ bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - close_fds=True, + close_fds=False if WIN32 else True, env={}) self.popenlock = None self.currenttimeout = None diff --git a/rpython/translator/sandbox/test/test_sandbox.py b/rpython/translator/sandbox/test/test_sandbox.py --- a/rpython/translator/sandbox/test/test_sandbox.py +++ b/rpython/translator/sandbox/test/test_sandbox.py @@ -2,43 +2,51 @@ import sys, os, time import struct import subprocess +import signal from rpython.rtyper.lltypesystem import rffi from rpython.translator.interactive import Translation from rpython.translator.sandbox.sandlib import read_message, write_message from rpython.translator.sandbox.sandlib import write_exception +if hasattr(signal, 'alarm'): + _orig_read_message = read_message + + def _timed_out(*args): + raise EOFError("timed out waiting for data") + + def read_message(f): + signal.signal(signal.SIGALRM, _timed_out) + signal.alarm(20) + try: + return _orig_read_message(f) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, signal.SIG_DFL) + def expect(f, g, fnname, args, result, resulttype=None): - msg = read_message(f, timeout=10.0) + msg = read_message(f) assert msg == fnname - msg = read_message(f, timeout=10.0) + msg = read_message(f) assert msg == args if isinstance(result, Exception): write_exception(g, result) else: write_message(g, 0) write_message(g, result, resulttype) - g.flush() + g.flush() def compile(f, gc='ref'): t = Translation(f, backend='c', sandbox=True, gc=gc, check_str_without_nul=True) return str(t.compile()) -unsupported_platform = ('False', '') -if sys.platform == 'win32': - unsupported_platform = ('True', 'sandbox not supported on this platform') - def test_unavailable(): - def entry_point(argv): - fd = os.open("/tmp/foobar", os.O_RDONLY, 0777) - os.close(fd) - return 0 - exc = py.test.raises(TypeError, compile, entry_point) - assert str(exc).find('not supported') >= 0 +def run_in_subprocess(exe): + popen = subprocess.Popen(exe, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return popen.stdin, popen.stdout -supported = py.test.mark.skipif(unsupported_platform[0], reason=unsupported_platform[1]) - - at supported def test_open_dup(): def entry_point(argv): fd = os.open("/tmp/foobar", os.O_RDONLY, 0777) @@ -48,7 +56,7 @@ return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_os.ll_os_open", ("/tmp/foobar", os.O_RDONLY, 0777), 77) expect(f, g, "ll_os.ll_os_dup", (77,), 78) g.close() @@ -56,7 +64,6 @@ f.close() assert tail == "" - at supported def test_read_write(): def entry_point(argv): fd = os.open("/tmp/foobar", os.O_RDONLY, 0777) @@ -69,7 +76,7 @@ return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_os.ll_os_open", ("/tmp/foobar", os.O_RDONLY, 0777), 77) expect(f, g, "ll_os.ll_os_read", (77, 123), "he\x00llo") expect(f, g, "ll_os.ll_os_write", (77, "world\x00!\x00"), 42) @@ -79,7 +86,6 @@ f.close() assert tail == "" - at supported def test_dup2_access(): def entry_point(argv): os.dup2(34, 56) @@ -87,7 +93,7 @@ return 1 - y exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_os.ll_os_dup2", (34, 56), None) expect(f, g, "ll_os.ll_os_access", ("spam", 77), True) g.close() @@ -95,19 +101,21 @@ f.close() assert tail == "" - at supported def test_stat_ftruncate(): from rpython.translator.sandbox.sandlib import RESULTTYPE_STATRESULT from rpython.rlib.rarithmetic import r_longlong r0x12380000007 = r_longlong(0x12380000007) + if not hasattr(os, 'ftruncate'): + py.test.skip("posix only") + def entry_point(argv): st = os.stat("somewhere") os.ftruncate(st.st_mode, st.st_size) # nonsense, just to see outside return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) st = os.stat_result((55, 0, 0, 0, 0, 0, 0x12380000007, 0, 0, 0)) expect(f, g, "ll_os.ll_os_stat", ("somewhere",), st, resulttype = RESULTTYPE_STATRESULT) @@ -117,7 +125,6 @@ f.close() assert tail == "" - at supported def test_time(): def entry_point(argv): t = time.time() @@ -125,7 +132,7 @@ return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_time.ll_time_time", (), 3.141592) expect(f, g, "ll_os.ll_os_dup", (3141,), 3) g.close() @@ -133,7 +140,6 @@ f.close() assert tail == "" - at supported def test_getcwd(): def entry_point(argv): t = os.getcwd() @@ -141,7 +147,7 @@ return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_os.ll_os_getcwd", (), "/tmp/foo/bar") expect(f, g, "ll_os.ll_os_dup", (len("/tmp/foo/bar"),), 3) g.close() @@ -149,7 +155,6 @@ f.close() assert tail == "" - at supported def test_oserror(): def entry_point(argv): try: @@ -159,7 +164,7 @@ return 0 exe = compile(entry_point) - g, f = os.popen2(exe, "t", 0) + g, f = run_in_subprocess(exe) expect(f, g, "ll_os.ll_os_stat", ("somewhere",), OSError(6321, "egg")) expect(f, g, "ll_os.ll_os_close", (6321,), None) g.close() @@ -167,7 +172,6 @@ f.close() assert tail == "" - at supported def test_hybrid_gc(): def entry_point(argv): l = [] @@ -192,7 +196,6 @@ rescode = pipe.wait() assert rescode == 0 - at supported def test_segfault_1(): class A: def __init__(self, m): @@ -206,16 +209,12 @@ return int(x.m) exe = compile(entry_point) - g, f, e = os.popen3(exe, "t", 0) + g, f = run_in_subprocess(exe) g.close() tail = f.read() f.close() - assert tail == "" - errors = e.read() - e.close() - assert 'Invalid RPython operation' in errors + assert 'Invalid RPython operation' in tail - at supported def test_segfault_2(): py.test.skip("hum, this is one example, but we need to be very careful") class Base: @@ -248,7 +247,6 @@ e.close() assert '...think what kind of errors to get...' in errors - at supported def test_safe_alloc(): from rpython.rlib.rmmap import alloc, free @@ -269,7 +267,6 @@ rescode = pipe.wait() assert rescode == 0 - at supported def test_unsafe_mmap(): py.test.skip("Since this stuff is unimplemented, it won't work anyway " "however, the day it starts working, it should pass test") @@ -295,7 +292,6 @@ rescode = pipe.wait() assert rescode == 0 - at supported class TestPrintedResults: def run(self, entry_point, args, expected): diff --git a/rpython/translator/sandbox/test/test_sandlib.py b/rpython/translator/sandbox/test/test_sandlib.py --- a/rpython/translator/sandbox/test/test_sandlib.py +++ b/rpython/translator/sandbox/test/test_sandlib.py @@ -6,10 +6,10 @@ from rpython.translator.sandbox.sandlib import SimpleIOSandboxedProc from rpython.translator.sandbox.sandlib import VirtualizedSandboxedProc from rpython.translator.sandbox.sandlib import VirtualizedSocketProc -from rpython.translator.sandbox.test.test_sandbox import compile, supported +from rpython.translator.sandbox.test.test_sandbox import compile from rpython.translator.sandbox.vfs import Dir, File, RealDir, RealFile - at supported + class MockSandboxedProc(SandboxedProc): """A sandbox process wrapper that replays expected syscalls.""" @@ -35,7 +35,7 @@ do_ll_os__ll_os_write = _make_method("write") do_ll_os__ll_os_close = _make_method("close") - at supported + def test_lib(): def entry_point(argv): fd = os.open("/tmp/foobar", os.O_RDONLY, 0777) @@ -63,7 +63,6 @@ proc.handle_forever() assert proc.seen == len(proc.expected) - at supported def test_foobar(): py.test.skip("to be updated") foobar = rffi.llexternal("foobar", [rffi.CCHARP], rffi.LONG) @@ -80,7 +79,6 @@ proc.handle_forever() assert proc.seen == len(proc.expected) - at supported def test_simpleio(): def entry_point(argv): print "Please enter a number:" @@ -102,7 +100,6 @@ assert output == "Please enter a number:\nThe double is: 42\n" assert error == "" - at supported def test_socketio(): class SocketProc(VirtualizedSocketProc, SimpleIOSandboxedProc): def build_virtual_root(self): @@ -119,7 +116,6 @@ output, error = proc.communicate("") assert output.startswith('HTTP/1.1 301 Moved Permanently') - at supported def test_oserror(): def entry_point(argv): try: @@ -137,7 +133,6 @@ assert proc.seen == len(proc.expected) - at supported class SandboxedProcWithFiles(VirtualizedSandboxedProc, SimpleIOSandboxedProc): """A sandboxed process with a simple virtualized filesystem. @@ -150,7 +145,6 @@ 'this.pyc': RealFile(__file__), }) - at supported def test_too_many_opens(): def entry_point(argv): try: @@ -192,7 +186,6 @@ assert output == "All ok!\n" assert error == "" - at supported def test_fstat(): def compare(a, b, i): if a != b: @@ -226,7 +219,6 @@ assert output == "All ok!\n" assert error == "" - at supported def test_lseek(): def char_should_be(c, should): if c != should: @@ -256,8 +248,10 @@ assert output == "All ok!\n" assert error == "" - at supported def test_getuid(): + if not hasattr(os, 'getuid'): + py.test.skip("posix only") + def entry_point(argv): import os print "uid is %s" % os.getuid() diff --git a/rpython/translator/sandbox/test/test_vfs.py b/rpython/translator/sandbox/test/test_vfs.py --- a/rpython/translator/sandbox/test/test_vfs.py +++ b/rpython/translator/sandbox/test/test_vfs.py @@ -2,13 +2,10 @@ import sys, stat, os from rpython.translator.sandbox.vfs import * from rpython.tool.udir import udir -from rpython.translator.sandbox.test.test_sandbox import unsupported_platform HASLINK = hasattr(os, 'symlink') def setup_module(mod): - if unsupported_platform[0] == 'True': - py.test.skip(unsupported_platform[1]) d = udir.ensure('test_vfs', dir=1) d.join('file1').write('somedata1') d.join('file2').write('somelongerdata2') @@ -70,11 +67,12 @@ f = v_test_vfs.join('file2') assert f.getsize() == len('somelongerdata2') - py.test.raises(OSError, f.open) + if os.name != 'nt': # can't have unreadable files there? + py.test.raises(OSError, f.open) py.test.raises(OSError, v_test_vfs.join, 'does_not_exist') py.test.raises(OSError, v_test_vfs.join, 'symlink3') - if follow_links: + if follow_links and HASLINK: d = v_test_vfs.join('symlink1') assert stat.S_ISDIR(d.stat().st_mode) assert d.keys() == ['subfile1'] From noreply at buildbot.pypy.org Sat Sep 19 10:01:15 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 10:01:15 +0200 (CEST) Subject: [pypy-commit] pypy default: 32-bit fix Message-ID: <20150919080115.419471C11E1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79703:28be3e83023d Date: 2015-09-19 10:01 +0200 http://bitbucket.org/pypy/pypy/changeset/28be3e83023d/ Log: 32-bit fix diff --git a/rpython/jit/metainterp/test/test_executor.py b/rpython/jit/metainterp/test/test_executor.py --- a/rpython/jit/metainterp/test/test_executor.py +++ b/rpython/jit/metainterp/test/test_executor.py @@ -109,7 +109,7 @@ box2 = boxfloat(222.2) fielddescr = FakeFieldDescr() _execute_arglist(cpu, None, rop.SETFIELD_GC, [box1, box2], fielddescr) - assert cpu.fakesetfield == (box1.getref_base(), box2.getfloat(), + assert cpu.fakesetfield == (box1.getref_base(), box2.getfloatstorage(), fielddescr) # arity == 3 box3 = InputArgInt(33) @@ -117,7 +117,7 @@ _execute_arglist(cpu, None, rop.SETARRAYITEM_GC, [box1, box3, box2], arraydescr) assert cpu.fakesetarrayitem == (box1.getref_base(), box3.getint(), - box2.getfloat(), arraydescr) + box2.getfloatstorage(), arraydescr) # cases without descr # arity == 1 box = _execute_arglist(cpu, None, rop.INT_INVERT, [box3]) From noreply at buildbot.pypy.org Sat Sep 19 12:14:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 12:14:31 +0200 (CEST) Subject: [pypy-commit] pypy gc-more-incremental: Branch to remove a source of non-incremental-ness in the GC Message-ID: <20150919101431.40E371C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: gc-more-incremental Changeset: r79704:e5b0d1a920c0 Date: 2015-09-19 11:25 +0200 http://bitbucket.org/pypy/pypy/changeset/e5b0d1a920c0/ Log: Branch to remove a source of non-incremental-ness in the GC From noreply at buildbot.pypy.org Sat Sep 19 12:14:33 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 12:14:33 +0200 (CEST) Subject: [pypy-commit] pypy gc-more-incremental: This is mostly an attempt to change the threshold in external_malloc() Message-ID: <20150919101433.757661C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: gc-more-incremental Changeset: r79705:264a78afb911 Date: 2015-09-19 12:14 +0200 http://bitbucket.org/pypy/pypy/changeset/264a78afb911/ Log: This is mostly an attempt to change the threshold in external_malloc() diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -754,14 +754,30 @@ self.minor_collection() if minor_collection_count == 1: # - # If the gc_state is not STATE_SCANNING, we're in the middle of - # an incremental major collection. In this case, always progress - # one step. If the gc_state is STATE_SCANNING, wait until there - # is too much garbage before starting the next major collection. + # If the gc_state is STATE_SCANNING, we're not in + # the middle of an incremental major collection. + # In that case, wait until there is too much + # garbage before starting the next major + # collection. But if we are in the middle of an + # incremental major collection, then always do (at + # least) one step now. + # + # This will increment next_major_collection_threshold + # by nursery_size//2. If more than nursery_size//2 + # survives, then threshold_reached() might still be + # true after that. In that case we do a second step. + # The goal is to avoid too high memory peaks if the + # program allocates a lot of surviving objects. + # if (self.gc_state != STATE_SCANNING or - self.get_total_memory_used() > - self.next_major_collection_threshold): + self.threshold_reached()): + self.major_collection_step() + + if (self.gc_state != STATE_SCANNING and + self.threshold_reached()): # ^^but only if still + self.minor_collection() # the same collection + self.major_collection_step() # # The nursery might not be empty now, because of # execute_finalizers(). If it is almost full again, @@ -825,17 +841,25 @@ raise MemoryError # # If somebody calls this function a lot, we must eventually - # force a collection. XXX make this more incremental! For now - # the logic is to first do a minor GC only, and check if that - # was enough to free a bunch of large young objects. If not, - # we do a complete major GC. - if self.get_total_memory_free() < raw_malloc_usage(totalsize): + # force a collection. We use threshold_reached(), which might + # be true now but become false at some point after a few calls + # to major_collection_step(). If there is really no memory, + # then when the major collection finishes it will raise + # MemoryError. + # + # The logic is to first do a minor GC only, and check if that + # was enough to free a bunch of large young objects. If it + # was, then we don't do any major collection step. + # + while self.threshold_reached(raw_malloc_usage(totalsize)): self.minor_collection() - if self.get_total_memory_free() < (raw_malloc_usage(totalsize) + - self.nursery_size // 2): - self.gc_step_until(STATE_SWEEPING) - self.gc_step_until(STATE_FINALIZING, - raw_malloc_usage(totalsize)) + if self.threshold_reached(raw_malloc_usage(totalsize) + + self.nursery_size // 2): + self.major_collection_step(raw_malloc_usage(totalsize)) + # note that this loop should not be infinite: when the + # last step of a major collection is done but + # threshold_reached(totalsize) is still true, then + # we should get a MemoryError from major_collection_step(). # # Check if the object would fit in the ArenaCollection. if raw_malloc_usage(totalsize) <= self.small_request_threshold: @@ -1112,9 +1136,9 @@ """ return self.ac.total_memory_used + self.rawmalloced_total_size - def get_total_memory_free(self): + def threshold_reached(self, extra=0): return (self.next_major_collection_threshold - - float(self.get_total_memory_used())) + float(self.get_total_memory_used())) < float(extra) def card_marking_words_for_length(self, length): # --- Unoptimized version: @@ -2058,10 +2082,10 @@ self.gc_step_until(STATE_MARKING) self.gc_step_until(STATE_SCANNING) - def gc_step_until(self, state, reserving_size=0): + def gc_step_until(self, state): while self.gc_state != state: self.minor_collection() - self.major_collection_step(reserving_size) + self.major_collection_step() debug_gc_step_until = gc_step_until # xxx @@ -2086,8 +2110,36 @@ pass self.debug_check_consistency() + # + # Every call to major_collection_step() adds nursery_size//2 + # to the threshold. It is reset at the end of this function + # when the major collection is fully finished. + # + # In the common case, this is larger than the size of all + # objects that survive a minor collection. After a few + # minor collections (each followed by one call to + # major_collection_step()) the threshold is much higher than + # the currently-in-use old memory. Then threshold_reached() + # won't be true again until the major collection fully + # finishes, time passes, and it's time for the next major + # collection. + # + # However there are less common cases: + # + # * if more than half of the nursery consistently survives: we + # call major_collection_step() twice after a minor + # collection; + # + # * or if we're allocating a large number of bytes in + # external_malloc(). In that case, we are likely to reach + # again the threshold_reached() case, and more major + # collection steps will be done immediately until + # threshold_reached() returns false. + # + self.next_major_collection_threshold += self.nursery_size // 2 - # XXX currently very course increments, get this working then split + + # XXX currently very coarse increments, get this working then split # to smaller increments using stacks for resuming if self.gc_state == STATE_SCANNING: self.objects_to_trace = self.AddressStack() @@ -2201,8 +2253,7 @@ # # Max heap size: gives an upper bound on the threshold. If we # already have at least this much allocated, raise MemoryError. - if bounded and (float(self.get_total_memory_used()) + reserving_size >= - self.next_major_collection_initial): + if bounded and self.threshold_reached(reserving_size): # # First raise MemoryError, giving the program a chance to # quit cleanly. It might still allocate in the nursery, From noreply at buildbot.pypy.org Sat Sep 19 13:38:59 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 13:38:59 +0200 (CEST) Subject: [pypy-commit] pypy gc-more-incremental: checked, seems ready for merge Message-ID: <20150919113859.BC9ED1C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: gc-more-incremental Changeset: r79706:df9fde11963b Date: 2015-09-19 13:36 +0200 http://bitbucket.org/pypy/pypy/changeset/df9fde11963b/ Log: checked, seems ready for merge From noreply at buildbot.pypy.org Sat Sep 19 13:39:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 13:39:02 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge gc-more-incremental Message-ID: <20150919113902.1D2551C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79707:ba09f9a7c031 Date: 2015-09-19 13:39 +0200 http://bitbucket.org/pypy/pypy/changeset/ba09f9a7c031/ Log: hg merge gc-more-incremental Remove a source of non-incremental-ness in the GC: now external_malloc() no longer runs gc_step_until() any more. If there is a currently-running major collection, we do only so many steps before returning. This number of steps depends on the size of the allocated object. It is controlled by tracking the general progress of these major collection steps and the size of old objects that keep adding up between them. diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -754,14 +754,30 @@ self.minor_collection() if minor_collection_count == 1: # - # If the gc_state is not STATE_SCANNING, we're in the middle of - # an incremental major collection. In this case, always progress - # one step. If the gc_state is STATE_SCANNING, wait until there - # is too much garbage before starting the next major collection. + # If the gc_state is STATE_SCANNING, we're not in + # the middle of an incremental major collection. + # In that case, wait until there is too much + # garbage before starting the next major + # collection. But if we are in the middle of an + # incremental major collection, then always do (at + # least) one step now. + # + # This will increment next_major_collection_threshold + # by nursery_size//2. If more than nursery_size//2 + # survives, then threshold_reached() might still be + # true after that. In that case we do a second step. + # The goal is to avoid too high memory peaks if the + # program allocates a lot of surviving objects. + # if (self.gc_state != STATE_SCANNING or - self.get_total_memory_used() > - self.next_major_collection_threshold): + self.threshold_reached()): + self.major_collection_step() + + if (self.gc_state != STATE_SCANNING and + self.threshold_reached()): # ^^but only if still + self.minor_collection() # the same collection + self.major_collection_step() # # The nursery might not be empty now, because of # execute_finalizers(). If it is almost full again, @@ -825,17 +841,25 @@ raise MemoryError # # If somebody calls this function a lot, we must eventually - # force a collection. XXX make this more incremental! For now - # the logic is to first do a minor GC only, and check if that - # was enough to free a bunch of large young objects. If not, - # we do a complete major GC. - if self.get_total_memory_free() < raw_malloc_usage(totalsize): + # force a collection. We use threshold_reached(), which might + # be true now but become false at some point after a few calls + # to major_collection_step(). If there is really no memory, + # then when the major collection finishes it will raise + # MemoryError. + # + # The logic is to first do a minor GC only, and check if that + # was enough to free a bunch of large young objects. If it + # was, then we don't do any major collection step. + # + while self.threshold_reached(raw_malloc_usage(totalsize)): self.minor_collection() - if self.get_total_memory_free() < (raw_malloc_usage(totalsize) + - self.nursery_size // 2): - self.gc_step_until(STATE_SWEEPING) - self.gc_step_until(STATE_FINALIZING, - raw_malloc_usage(totalsize)) + if self.threshold_reached(raw_malloc_usage(totalsize) + + self.nursery_size // 2): + self.major_collection_step(raw_malloc_usage(totalsize)) + # note that this loop should not be infinite: when the + # last step of a major collection is done but + # threshold_reached(totalsize) is still true, then + # we should get a MemoryError from major_collection_step(). # # Check if the object would fit in the ArenaCollection. if raw_malloc_usage(totalsize) <= self.small_request_threshold: @@ -1112,9 +1136,9 @@ """ return self.ac.total_memory_used + self.rawmalloced_total_size - def get_total_memory_free(self): + def threshold_reached(self, extra=0): return (self.next_major_collection_threshold - - float(self.get_total_memory_used())) + float(self.get_total_memory_used())) < float(extra) def card_marking_words_for_length(self, length): # --- Unoptimized version: @@ -2058,10 +2082,10 @@ self.gc_step_until(STATE_MARKING) self.gc_step_until(STATE_SCANNING) - def gc_step_until(self, state, reserving_size=0): + def gc_step_until(self, state): while self.gc_state != state: self.minor_collection() - self.major_collection_step(reserving_size) + self.major_collection_step() debug_gc_step_until = gc_step_until # xxx @@ -2086,8 +2110,36 @@ pass self.debug_check_consistency() + # + # Every call to major_collection_step() adds nursery_size//2 + # to the threshold. It is reset at the end of this function + # when the major collection is fully finished. + # + # In the common case, this is larger than the size of all + # objects that survive a minor collection. After a few + # minor collections (each followed by one call to + # major_collection_step()) the threshold is much higher than + # the currently-in-use old memory. Then threshold_reached() + # won't be true again until the major collection fully + # finishes, time passes, and it's time for the next major + # collection. + # + # However there are less common cases: + # + # * if more than half of the nursery consistently survives: we + # call major_collection_step() twice after a minor + # collection; + # + # * or if we're allocating a large number of bytes in + # external_malloc(). In that case, we are likely to reach + # again the threshold_reached() case, and more major + # collection steps will be done immediately until + # threshold_reached() returns false. + # + self.next_major_collection_threshold += self.nursery_size // 2 - # XXX currently very course increments, get this working then split + + # XXX currently very coarse increments, get this working then split # to smaller increments using stacks for resuming if self.gc_state == STATE_SCANNING: self.objects_to_trace = self.AddressStack() @@ -2201,8 +2253,7 @@ # # Max heap size: gives an upper bound on the threshold. If we # already have at least this much allocated, raise MemoryError. - if bounded and (float(self.get_total_memory_used()) + reserving_size >= - self.next_major_collection_initial): + if bounded and self.threshold_reached(reserving_size): # # First raise MemoryError, giving the program a chance to # quit cleanly. It might still allocate in the nursery, From noreply at buildbot.pypy.org Sat Sep 19 13:39:57 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 13:39:57 +0200 (CEST) Subject: [pypy-commit] pypy default: Document branch Message-ID: <20150919113957.068301C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79708:57d78cbc567a Date: 2015-09-19 13:40 +0200 http://bitbucket.org/pypy/pypy/changeset/57d78cbc567a/ Log: Document branch 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 @@ -21,3 +21,12 @@ .. branch: missing_openssl_include Fix for missing headers in OpenBSD, already applied in downstream ports + +.. branch: gc-more-incremental +Remove a source of non-incremental-ness in the GC: now +external_malloc() no longer runs gc_step_until() any more. If there +is a currently-running major collection, we do only so many steps +before returning. This number of steps depends on the size of the +allocated object. It is controlled by tracking the general progress +of these major collection steps and the size of old objects that +keep adding up between them. From noreply at buildbot.pypy.org Sat Sep 19 14:02:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 19 Sep 2015 14:02:24 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150919120224.47AA91C0FF9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r638:75105e9862ea Date: 2015-09-19 14:03 +0200 http://bitbucket.org/pypy/pypy.org/changeset/75105e9862ea/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -9,13 +9,13 @@ - $60498 of $105000 (57.6%) + $60560 of $105000 (57.7%)
    @@ -23,7 +23,7 @@
  • diff --git a/don4.html b/don4.html --- a/don4.html +++ b/don4.html @@ -17,7 +17,7 @@ 2nd call: - $29421 of $80000 (36.8%) + $29431 of $80000 (36.8%)
    @@ -25,7 +25,7 @@
  • From noreply at buildbot.pypy.org Sun Sep 20 08:54:29 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 08:54:29 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: reenable jit hooks and pass all the untranslated tests Message-ID: <20150920065429.4F4AA1C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79709:41627817b1f7 Date: 2015-09-20 08:54 +0200 http://bitbucket.org/pypy/pypy/changeset/41627817b1f7/ Log: reenable jit hooks and pass all the untranslated tests diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - from pypy.module.pypyjit.interp_jit import pypy_hooks - #from pypy.module.pypyjit.hooks import pypy_hooks + from pypy.module.pypyjit.hooks import pypy_hooks return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -12,25 +12,22 @@ 'dont_trace_here': 'interp_jit.dont_trace_here', 'trace_next_iteration': 'interp_jit.trace_next_iteration', 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', - 'set_compile_bridge': 'interp_jit.set_compile_bridge', - 'set_compile_loop': 'interp_jit.set_compile_loop', - #'set_compile_hook': 'interp_resop.set_compile_hook', - #'set_optimize_hook': 'interp_resop.set_optimize_hook', - #'set_abort_hook': 'interp_resop.set_abort_hook', - #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - #'enable_debug': 'interp_resop.enable_debug', - #'disable_debug': 'interp_resop.disable_debug', - #'ResOperation': 'interp_resop.WrappedOp', - #'DebugMergePoint': 'interp_resop.DebugMergePoint', - #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - #'Box': 'interp_resop.WrappedBox', + 'set_compile_hook': 'interp_resop.set_compile_hook', + 'set_optimize_hook': 'interp_resop.set_optimize_hook', + 'set_abort_hook': 'interp_resop.set_abort_hook', + 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + 'enable_debug': 'interp_resop.enable_debug', + 'disable_debug': 'interp_resop.disable_debug', + 'ResOperation': 'interp_resop.WrappedOp', + 'DebugMergePoint': 'interp_resop.DebugMergePoint', + 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } def setup_after_space_initialization(self): # force the __extend__ hacks to occur early from pypy.module.pypyjit.interp_jit import pypyjitdriver - from pypy.module.pypyjit.interp_jit import pypy_hooks + from pypy.module.pypyjit.hooks import pypy_hooks # add the 'defaults' attribute from rpython.rlib.jit import PARAMETERS space = self.space diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -46,7 +46,8 @@ if cache.in_recursion: return if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.compile_hook_with_ops) cache.in_recursion = True try: try: @@ -63,7 +64,8 @@ if cache.in_recursion: return if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.optimize_hook_with_ops) cache.in_recursion = True try: try: diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -221,70 +221,70 @@ jit_hooks.trace_next_iteration_hash('pypyjit', hash) return space.w_None -class Cache(object): - in_recursion = False +# class Cache(object): +# in_recursion = False - def __init__(self, space): - self.w_compile_bridge = space.w_None - self.w_compile_loop = space.w_None +# def __init__(self, space): +# self.w_compile_bridge = space.w_None +# self.w_compile_loop = space.w_None -def set_compile_bridge(space, w_hook): - cache = space.fromcache(Cache) - assert w_hook is not None - cache.w_compile_bridge = w_hook +# def set_compile_bridge(space, w_hook): +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_bridge = w_hook -def set_compile_loop(space, w_hook): - from rpython.rlib.nonconst import NonConstant +# def set_compile_loop(space, w_hook): +# from rpython.rlib.nonconst import NonConstant - cache = space.fromcache(Cache) - assert w_hook is not None - cache.w_compile_loop = w_hook - cache.in_recursion = NonConstant(False) +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_loop = w_hook +# cache.in_recursion = NonConstant(False) -class PyPyJitHookInterface(JitHookInterface): - def after_compile(self, debug_info): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - l_w = [] - if not space.is_true(cache.w_compile_loop): - return - for i, op in enumerate(debug_info.operations): - if op.is_guard(): - w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) - l_w.append(w_t) - try: - cache.in_recursion = True - try: - space.call_function(cache.w_compile_loop, space.newlist(l_w)) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) - finally: - cache.in_recursion = False +# class PyPyJitHookInterface(JitHookInterface): +# def after_compile(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# l_w = [] +# if not space.is_true(cache.w_compile_loop): +# return +# for i, op in enumerate(debug_info.operations): +# if op.is_guard(): +# w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) +# l_w.append(w_t) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_loop, space.newlist(l_w)) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False - def after_compile_bridge(self, debug_info): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if not space.is_true(cache.w_compile_bridge): - return - w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) - try: - cache.in_recursion = True - try: - space.call_function(cache.w_compile_bridge, w_hash) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) - finally: - cache.in_recursion = False +# def after_compile_bridge(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# if not space.is_true(cache.w_compile_bridge): +# return +# w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_bridge, w_hash) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False - def before_compile(self, debug_info): - pass +# def before_compile(self, debug_info): +# pass - def before_compile_bridge(self, debug_info): - pass +# def before_compile_bridge(self, debug_info): +# pass -pypy_hooks = PyPyJitHookInterface() +# pypy_hooks = PyPyJitHookInterface() diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -43,8 +43,9 @@ else: return space.wrap(greenkey_repr) -def set_compile_hook(space, w_hook): - """ set_compile_hook(hook) + at unwrap_spec(operations=bool) +def set_compile_hook(space, w_hook, operations=True): + """ set_compile_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -58,10 +59,12 @@ cache = space.fromcache(Cache) assert w_hook is not None cache.w_compile_hook = w_hook + cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) -def set_optimize_hook(space, w_hook): - """ set_optimize_hook(hook) + at unwrap_spec(operations=bool) +def set_optimize_hook(space, w_hook, operations=True): + """ set_optimize_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is optimized, but before assembler compilation. This allows adding additional @@ -74,6 +77,7 @@ """ cache = space.fromcache(Cache) cache.w_optimize_hook = w_hook + cache.optimize_hook_with_ops = operations cache.in_recursion = NonConstant(False) @@ -96,6 +100,9 @@ cache.in_recursion = NonConstant(False) def wrap_oplist(space, logops, operations, ops_offset=None): + # this function is called from the JIT + from rpython.jit.metainterp.resoperation import rop + l_w = [] jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd for op in operations: @@ -103,117 +110,58 @@ ofs = -1 else: ofs = ops_offset.get(op, 0) - if op.opnum == rop.DEBUG_MERGE_POINT: + num = op.getopnum() + name = op.getopname() + if num == rop.DEBUG_MERGE_POINT: jd_sd = jitdrivers_sd[op.getarg(0).getint()] greenkey = op.getarglist()[3:] repr = jd_sd.warmstate.get_location_str(greenkey) w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr) - l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op), + l_w.append(DebugMergePoint(space, name, logops.repr_of_resop(op), jd_sd.jitdriver.name, op.getarg(1).getint(), op.getarg(2).getint(), w_greenkey)) else: - l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs, - logops.repr_of_resop(op))) + l_w.append(WrappedOp(name, ofs, logops.repr_of_resop(op))) return l_w + at unwrap_spec(offset=int, repr=str, name=str) +def descr_new_resop(space, w_tp, name, offset=-1, repr=''): + return WrappedOp(name, offset, repr) -class WrappedBox(W_Root): - """ A class representing a single box - """ - def __init__(self, llbox): - self.llbox = llbox - - def descr_getint(self, space): - if not jit_hooks.box_isint(self.llbox): - raise OperationError(space.w_NotImplementedError, - space.wrap("Box has no int value")) - return space.wrap(jit_hooks.box_getint(self.llbox)) - - at unwrap_spec(no=int) -def descr_new_box(space, w_tp, no): - return WrappedBox(jit_hooks.boxint_new(no)) - -WrappedBox.typedef = TypeDef( - 'Box', - __new__ = interp2app(descr_new_box), - getint = interp2app(WrappedBox.descr_getint), -) - - at unwrap_spec(num=int, offset=int, repr=str, w_res=W_Root) -def descr_new_resop(space, w_tp, num, w_args, w_res, offset=-1, - repr=''): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - if space.is_none(w_res): - llres = jit_hooks.emptyval() - else: - if not isinstance(w_res, WrappedBox): - raise OperationError(space.w_TypeError, space.wrap( - "expected box type, got %s" % space.type(w_res))) - llres = w_res.llbox - return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr) - - at unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int) -def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id, + at unwrap_spec(repr=str, name=str, jd_name=str, call_depth=int, call_id=int) +def descr_new_dmp(space, w_tp, name, repr, jd_name, call_depth, call_id, w_greenkey): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - num = rop.DEBUG_MERGE_POINT - return DebugMergePoint(space, - jit_hooks.resop_new(num, args, jit_hooks.emptyval()), + return DebugMergePoint(space, name, repr, jd_name, call_depth, call_id, w_greenkey) class WrappedOp(W_Root): """ A class representing a single ResOperation, wrapped nicely """ - def __init__(self, op, offset, repr_of_resop): - self.op = op + def __init__(self, name, offset, repr_of_resop): self.offset = offset + self.name = name self.repr_of_resop = repr_of_resop def descr_repr(self, space): return space.wrap(self.repr_of_resop) - def descr_num(self, space): - return space.wrap(jit_hooks.resop_getopnum(self.op)) - def descr_name(self, space): - return space.wrap(hlstr(jit_hooks.resop_getopname(self.op))) - - @unwrap_spec(no=int) - def descr_getarg(self, space, no): - try: - box = jit_hooks.resop_getarg(self.op, no) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("Index out of range")) - return WrappedBox(box) - - @unwrap_spec(no=int, w_box=WrappedBox) - def descr_setarg(self, space, no, w_box): - jit_hooks.resop_setarg(self.op, no, w_box.llbox) - - def descr_getresult(self, space): - return WrappedBox(jit_hooks.resop_getresult(self.op)) - - def descr_setresult(self, space, w_box): - box = space.interp_w(WrappedBox, w_box) - jit_hooks.resop_setresult(self.op, box.llbox) + return space.wrap(self.name) class DebugMergePoint(WrappedOp): """ A class representing Debug Merge Point - the entry point to a jitted loop. """ - def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id, - w_greenkey): + def __init__(self, space, name, repr_of_resop, jd_name, call_depth, + call_id, w_greenkey): - WrappedOp.__init__(self, op, -1, repr_of_resop) + WrappedOp.__init__(self, name, -1, repr_of_resop) self.jd_name = jd_name self.call_depth = call_depth self.call_id = call_id @@ -237,12 +185,7 @@ __doc__ = WrappedOp.__doc__, __new__ = interp2app(descr_new_resop), __repr__ = interp2app(WrappedOp.descr_repr), - num = GetSetProperty(WrappedOp.descr_num), name = GetSetProperty(WrappedOp.descr_name), - getarg = interp2app(WrappedOp.descr_getarg), - setarg = interp2app(WrappedOp.descr_setarg), - result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult), offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.typedef.acceptable_as_base_class = False @@ -278,14 +221,18 @@ asmaddr = 0 asmlen = 0 - def __init__(self, space, debug_info, is_bridge=False): - logops = debug_info.logger._make_log_operations() - if debug_info.asminfo is not None: - ofs = debug_info.asminfo.ops_offset + def __init__(self, space, debug_info, is_bridge=False, wrap_ops=True): + if wrap_ops: + memo = {} + logops = debug_info.logger._make_log_operations(memo) + if debug_info.asminfo is not None: + ofs = debug_info.asminfo.ops_offset + else: + ofs = {} + ops = debug_info.operations + self.w_ops = space.newlist(wrap_oplist(space, logops, ops, ofs)) else: - ofs = {} - self.w_ops = space.newlist( - wrap_oplist(space, logops, debug_info.operations, ofs)) + self.w_ops = space.w_None self.jd_name = debug_info.get_jitdriver().name self.type = debug_info.type diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -136,7 +136,6 @@ assert dmp.call_id == 0 assert dmp.offset == -1 assert int_add.name == 'int_add' - assert int_add.num == self.int_add_num assert int_add.offset == 0 self.on_compile_bridge() expected = (' Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79710:03850deeb619 Date: 2015-09-20 09:14 +0200 http://bitbucket.org/pypy/pypy/changeset/03850deeb619/ Log: kill optimize_hook was never usefull anyway diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -13,7 +13,6 @@ 'trace_next_iteration': 'interp_jit.trace_next_iteration', 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', 'set_compile_hook': 'interp_resop.set_compile_hook', - 'set_optimize_hook': 'interp_resop.set_optimize_hook', 'set_abort_hook': 'interp_resop.set_abort_hook', 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', 'enable_debug': 'interp_resop.enable_debug', diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -35,10 +35,10 @@ self._compile_hook(debug_info, is_bridge=True) def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) + pass def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) + pass def _compile_hook(self, debug_info, is_bridge): space = self.space @@ -58,34 +58,4 @@ finally: cache.in_recursion = False - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, - cache.optimize_hook_with_ops) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -22,7 +22,6 @@ def __init__(self, space): self.w_compile_hook = space.w_None self.w_abort_hook = space.w_None - self.w_optimize_hook = space.w_None def getno(self): self.no += 1 @@ -62,25 +61,6 @@ cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) - at unwrap_spec(operations=bool) -def set_optimize_hook(space, w_hook, operations=True): - """ set_optimize_hook(hook, operations=True) - - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's - docstring for details. - - Result value will be the resulting list of operations, or None - """ - cache = space.fromcache(Cache) - cache.w_optimize_hook = w_hook - cache.optimize_hook_with_ops = operations - cache.in_recursion = NonConstant(False) - - def set_abort_hook(space, w_hook): """ set_abort_hook(hook) From noreply at buildbot.pypy.org Sun Sep 20 09:21:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 09:21:12 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: improve the docs Message-ID: <20150920072112.3EE9F1C1205@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79711:9d6230ead66e Date: 2015-09-20 09:21 +0200 http://bitbucket.org/pypy/pypy/changeset/9d6230ead66e/ Log: improve the docs diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -5,19 +5,8 @@ understanding what's pypy's JIT doing while running your program. There are three functions related to that coming from the ``pypyjit`` module: -.. function:: set_optimize_hook(callable) - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The callable will be called with the ``pypyjit.JitLoopInfo`` object. - Refer to it's documentation for details. - - Result value will be the resulting list of operations, or None - - -.. function:: set_compile_hook(callable) +.. function:: set_compile_hook(callable, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -28,6 +17,9 @@ inside the jit hook is itself jitted, it will get compiled, but the jit hook won't be called for that. + if operations=False, no list of operations will be available. Useful + if the hook is supposed to be very lighweight. + .. function:: set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing @@ -66,3 +58,25 @@ * ``loop_run_times`` - counters for number of times loops are run, only works when ``enable_debug`` is called. + +.. class:: JitLoopInfo + + A class containing information about the compiled loop. Usable attributes: + + * ``operations`` - list of operations, if requested + + * ``jitdriver_name`` - the name of jitdriver associated with this loop + + * ``greenkey`` - a key at which the loop got compiled (e.g. code position, + is_being_profiled, pycode tuple for python jitdriver) + + * ``loop_no`` - loop cardinal number + + * ``bridge_no`` - id of the fail descr + + * ``type`` - "entry bridge", "loop" or "bridge" + + * ``asmaddr`` - an address in raw memory where assembler resides + + * ``asmlen`` - length of raw memory with assembler associated + From noreply at buildbot.pypy.org Sun Sep 20 09:54:55 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 20 Sep 2015 09:54:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Probable fix Message-ID: <20150920075455.945CD1C0726@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79712:eb4870ddb1a7 Date: 2015-09-20 09:55 +0200 http://bitbucket.org/pypy/pypy/changeset/eb4870ddb1a7/ Log: Probable fix diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -47,7 +47,7 @@ i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) - p34 = new_with_vtable(#) + p34 = new_with_vtable(descr=...) {{{ setfield_gc(p34, p1, descr=) setfield_gc(p34, i25, descr=) @@ -154,7 +154,7 @@ f86 = float_add(f74, f85) i87 = int_add(i76, 1) --TICK-- - jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...) + jump(..., descr=...) """) def test_array_flatiter_next(self): From noreply at buildbot.pypy.org Sun Sep 20 10:02:49 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 20 Sep 2015 10:02:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Change the default gcrootfinder: "asmgcc" should be used only on x86 or Message-ID: <20150920080249.D008F1C1DD9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79713:3b058e5d5c33 Date: 2015-09-20 10:03 +0200 http://bitbucket.org/pypy/pypy/changeset/3b058e5d5c33/ Log: Change the default gcrootfinder: "asmgcc" should be used only on x86 or x86-64 Linux diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -16,10 +16,11 @@ DEFL_GC = "incminimark" # XXX +DEFL_ROOTFINDER_WITHJIT = "shadowstack" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" -else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + _mach = os.popen('uname -m', 'r').read().strip() + if _mach.startswith('x86') or _mach in ['i386', 'i486', 'i586', 'i686']: + DEFL_ROOTFINDER_WITHJIT = "asmgcc" # only for Linux on x86 / x86-64 IS_64_BITS = sys.maxint > 2147483647 From noreply at buildbot.pypy.org Sun Sep 20 10:07:07 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:07:07 +0200 (CEST) Subject: [pypy-commit] pypy default: a test and a fix Message-ID: <20150920080707.9C96D1C1E49@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79714:e809b9eb72e9 Date: 2015-09-20 10:06 +0200 http://bitbucket.org/pypy/pypy/changeset/e809b9eb72e9/ Log: a test and a fix diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -469,11 +469,9 @@ if op is None: continue val = op.getarg(1) - if val.type == 'r': - ptrinfo = self.getptrinfo(val) - if ptrinfo and ptrinfo.is_virtual(): - pendingfields.append(op) - continue + if self.optimizer.is_virtual(val): + pendingfields.append(op) + continue cf.force_lazy_setfield(self, descr) for descr, submap in self.cached_arrayitems.iteritems(): for index, cf in submap.iteritems(): @@ -486,12 +484,8 @@ # SETFIELD_GC or SETARRAYITEM_GC. opinfo = self.getptrinfo(op.getarg(0)) assert not opinfo.is_virtual() # it must be a non-virtual - if op.getarg(2).type == 'r': - fieldinfo = self.getptrinfo(op.getarg(2)) - if fieldinfo and fieldinfo.is_virtual(): - pendingfields.append(op) - else: - cf.force_lazy_setfield(self, descr) + if self.optimizer.is_virtual(op.getarg(2)): + pendingfields.append(op) else: cf.force_lazy_setfield(self, descr) return pendingfields 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 @@ -651,6 +651,14 @@ op.getopnum(), argboxes, op.getdescr(), op.type) + def is_virtual(self, op): + if op.type == 'r': + opinfo = self.getptrinfo(op) + return opinfo and opinfo.is_virtual() + if op.type == 'i': + opinfo = self.getrawptrinfo(op) + return opinfo and opinfo.is_virtual() + def pure_reverse(self, op): import sys if self.optpure is None: 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 @@ -8881,5 +8881,26 @@ """ self.optimize_loop(ops, expected) + def test_pending_setfield_delayed_malloc(self): + ops = """ + [i0, p0] + i2 = call_i('malloc', 10, descr=raw_malloc_descr) + setarrayitem_raw(i2, 0, 13, descr=rawarraydescr) + setfield_gc(p0, i2, descr=valuedescr) + i1 = int_add(i0, 1) + i3 = int_lt(i1, 10) + guard_true(i3) [] + setfield_gc(p0, 0, descr=valuedescr) + jump(i1, p0) + """ + expected = """ + [i0, p0] + i1 = int_add(i0, 1) + i3 = int_lt(i1, 10) + guard_true(i3) [p0] + jump(i1, p0) + """ + self.optimize_loop(ops, expected) + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass 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 @@ -723,6 +723,7 @@ elif n == 7: a = 3 else: a = 2 x = intmask(x * 10 + a) + print "XXXXXXXXXXXXXX", x i += 1 return x res = self.meta_interp(f, [0], backendopt=True) diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1069,6 +1069,26 @@ res = self.meta_interp(run, [42], backendopt=True) assert res == 420 + def test_not_too_many_bridges(self): + jitdriver = JitDriver(greens = [], reds = 'auto') + + def f(i): + s = 0 + while i > 0: + jitdriver.jit_merge_point() + if i % 2 == 0: + s += 1 + elif i % 3 == 0: + s += 1 + elif i % 5 == 0: + s += 1 + elif i % 7 == 0: + s += 1 + i -= 1 + return s + + self.meta_interp(f, [30]) + self.check_trace_count(3) class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Sun Sep 20 10:07:09 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:07:09 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20150920080709.CA19E1C1E49@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79715:f0bd5bbe701a Date: 2015-09-20 10:07 +0200 http://bitbucket.org/pypy/pypy/changeset/f0bd5bbe701a/ Log: merge diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -47,7 +47,7 @@ i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) - p34 = new_with_vtable(#) + p34 = new_with_vtable(descr=...) {{{ setfield_gc(p34, p1, descr=) setfield_gc(p34, i25, descr=) @@ -154,7 +154,7 @@ f86 = float_add(f74, f85) i87 = int_add(i76, 1) --TICK-- - jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...) + jump(..., descr=...) """) def test_array_flatiter_next(self): diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -16,10 +16,11 @@ DEFL_GC = "incminimark" # XXX +DEFL_ROOTFINDER_WITHJIT = "shadowstack" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" -else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + _mach = os.popen('uname -m', 'r').read().strip() + if _mach.startswith('x86') or _mach in ['i386', 'i486', 'i586', 'i686']: + DEFL_ROOTFINDER_WITHJIT = "asmgcc" # only for Linux on x86 / x86-64 IS_64_BITS = sys.maxint > 2147483647 From noreply at buildbot.pypy.org Sun Sep 20 10:13:00 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 20 Sep 2015 10:13:00 +0200 (CEST) Subject: [pypy-commit] pypy default: translation Message-ID: <20150920081300.1504D1C103C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79716:c7918b175fe5 Date: 2015-09-20 10:13 +0200 http://bitbucket.org/pypy/pypy/changeset/c7918b175fe5/ Log: translation 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 @@ -658,6 +658,7 @@ if op.type == 'i': opinfo = self.getrawptrinfo(op) return opinfo and opinfo.is_virtual() + return False def pure_reverse(self, op): import sys From noreply at buildbot.pypy.org Sun Sep 20 10:14:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:14:12 +0200 (CEST) Subject: [pypy-commit] pypy default: that was not supposed to go in; Message-ID: <20150920081412.599CE1C103C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79717:21dcd377d3e2 Date: 2015-09-20 10:13 +0200 http://bitbucket.org/pypy/pypy/changeset/21dcd377d3e2/ Log: that was not supposed to go in; 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 @@ -723,7 +723,6 @@ elif n == 7: a = 3 else: a = 2 x = intmask(x * 10 + a) - print "XXXXXXXXXXXXXX", x i += 1 return x res = self.meta_interp(f, [0], backendopt=True) From noreply at buildbot.pypy.org Sun Sep 20 10:14:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:14:14 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20150920081414.693FC1C103C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79718:68a3aa218fad Date: 2015-09-20 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/68a3aa218fad/ Log: merge 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 @@ -658,6 +658,7 @@ if op.type == 'i': opinfo = self.getrawptrinfo(op) return opinfo and opinfo.is_virtual() + return False def pure_reverse(self, op): import sys From noreply at buildbot.pypy.org Sun Sep 20 10:43:08 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:43:08 +0200 (CEST) Subject: [pypy-commit] pypy remember-tracing-counts: close to be merged branch Message-ID: <20150920084308.27DAF1C0403@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remember-tracing-counts Changeset: r79719:111302d1caa8 Date: 2015-09-20 10:41 +0200 http://bitbucket.org/pypy/pypy/changeset/111302d1caa8/ Log: close to be merged branch From noreply at buildbot.pypy.org Sun Sep 20 10:43:10 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 10:43:10 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge remember-tracing-counts. It does not quite remember the tracing counts, Message-ID: <20150920084310.E069F1C0403@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79720:a1a333d5337a Date: 2015-09-20 10:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a1a333d5337a/ Log: Merge remember-tracing-counts. It does not quite remember the tracing counts, but does expose enough interface to do it yourself. Also reenables the jit hooks diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -5,19 +5,8 @@ understanding what's pypy's JIT doing while running your program. There are three functions related to that coming from the ``pypyjit`` module: -.. function:: set_optimize_hook(callable) - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The callable will be called with the ``pypyjit.JitLoopInfo`` object. - Refer to it's documentation for details. - - Result value will be the resulting list of operations, or None - - -.. function:: set_compile_hook(callable) +.. function:: set_compile_hook(callable, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -28,6 +17,9 @@ inside the jit hook is itself jitted, it will get compiled, but the jit hook won't be called for that. + if operations=False, no list of operations will be available. Useful + if the hook is supposed to be very lighweight. + .. function:: set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing @@ -66,3 +58,25 @@ * ``loop_run_times`` - counters for number of times loops are run, only works when ``enable_debug`` is called. + +.. class:: JitLoopInfo + + A class containing information about the compiled loop. Usable attributes: + + * ``operations`` - list of operations, if requested + + * ``jitdriver_name`` - the name of jitdriver associated with this loop + + * ``greenkey`` - a key at which the loop got compiled (e.g. code position, + is_being_profiled, pycode tuple for python jitdriver) + + * ``loop_no`` - loop cardinal number + + * ``bridge_no`` - id of the fail descr + + * ``type`` - "entry bridge", "loop" or "bridge" + + * ``asmaddr`` - an address in raw memory where assembler resides + + * ``asmlen`` - length of raw memory with assembler associated + diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - #from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy()#pypy_hooks) + from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,18 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - #'set_compile_hook': 'interp_resop.set_compile_hook', - #'set_optimize_hook': 'interp_resop.set_optimize_hook', - #'set_abort_hook': 'interp_resop.set_abort_hook', - #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - #'enable_debug': 'interp_resop.enable_debug', - #'disable_debug': 'interp_resop.disable_debug', - #'ResOperation': 'interp_resop.WrappedOp', - #'DebugMergePoint': 'interp_resop.DebugMergePoint', - #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - #'Box': 'interp_resop.WrappedBox', + 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', + 'dont_trace_here': 'interp_jit.dont_trace_here', + 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', + 'set_compile_hook': 'interp_resop.set_compile_hook', + 'set_abort_hook': 'interp_resop.set_abort_hook', + 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + 'enable_debug': 'interp_resop.enable_debug', + 'disable_debug': 'interp_resop.disable_debug', + 'ResOperation': 'interp_resop.WrappedOp', + 'DebugMergePoint': 'interp_resop.DebugMergePoint', + 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -35,10 +35,10 @@ self._compile_hook(debug_info, is_bridge=True) def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) + pass def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) + pass def _compile_hook(self, debug_info, is_bridge): space = self.space @@ -46,7 +46,8 @@ if cache.in_recursion: return if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.compile_hook_with_ops) cache.in_recursion = True try: try: @@ -57,33 +58,4 @@ finally: cache.in_recursion = False - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -5,11 +5,14 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside -from rpython.rlib import jit -from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rlib import jit, jit_hooks +from rpython.rlib.jit import current_trace_length, unroll_parameters,\ + JitHookInterface +from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.pycode import CO_GENERATOR, PyCode +from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame, Yield from pypy.interpreter.baseobjspace import W_Root @@ -188,3 +191,100 @@ __call__ = interp2app(W_NotFromAssembler.descr_call), ) W_NotFromAssembler.typedef.acceptable_as_base_class = False + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + return space.wrap(bool(jit_hooks.get_jitcell_at_key( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode))) + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.dont_trace_here( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.trace_next_iteration( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(hash=r_uint) + at dont_look_inside +def trace_next_iteration_hash(space, hash): + jit_hooks.trace_next_iteration_hash('pypyjit', hash) + return space.w_None + +# class Cache(object): +# in_recursion = False + +# def __init__(self, space): +# self.w_compile_bridge = space.w_None +# self.w_compile_loop = space.w_None + +# def set_compile_bridge(space, w_hook): +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_bridge = w_hook + +# def set_compile_loop(space, w_hook): +# from rpython.rlib.nonconst import NonConstant + +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_loop = w_hook +# cache.in_recursion = NonConstant(False) + +# class PyPyJitHookInterface(JitHookInterface): +# def after_compile(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# l_w = [] +# if not space.is_true(cache.w_compile_loop): +# return +# for i, op in enumerate(debug_info.operations): +# if op.is_guard(): +# w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) +# l_w.append(w_t) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_loop, space.newlist(l_w)) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def after_compile_bridge(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# if not space.is_true(cache.w_compile_bridge): +# return +# w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_bridge, w_hash) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def before_compile(self, debug_info): +# pass + +# def before_compile_bridge(self, debug_info): +# pass + +# pypy_hooks = PyPyJitHookInterface() + diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -22,7 +22,6 @@ def __init__(self, space): self.w_compile_hook = space.w_None self.w_abort_hook = space.w_None - self.w_optimize_hook = space.w_None def getno(self): self.no += 1 @@ -43,8 +42,9 @@ else: return space.wrap(greenkey_repr) -def set_compile_hook(space, w_hook): - """ set_compile_hook(hook) + at unwrap_spec(operations=bool) +def set_compile_hook(space, w_hook, operations=True): + """ set_compile_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -58,25 +58,9 @@ cache = space.fromcache(Cache) assert w_hook is not None cache.w_compile_hook = w_hook + cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) -def set_optimize_hook(space, w_hook): - """ set_optimize_hook(hook) - - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's - docstring for details. - - Result value will be the resulting list of operations, or None - """ - cache = space.fromcache(Cache) - cache.w_optimize_hook = w_hook - cache.in_recursion = NonConstant(False) - - def set_abort_hook(space, w_hook): """ set_abort_hook(hook) @@ -96,6 +80,9 @@ cache.in_recursion = NonConstant(False) def wrap_oplist(space, logops, operations, ops_offset=None): + # this function is called from the JIT + from rpython.jit.metainterp.resoperation import rop + l_w = [] jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd for op in operations: @@ -103,117 +90,58 @@ ofs = -1 else: ofs = ops_offset.get(op, 0) - if op.opnum == rop.DEBUG_MERGE_POINT: + num = op.getopnum() + name = op.getopname() + if num == rop.DEBUG_MERGE_POINT: jd_sd = jitdrivers_sd[op.getarg(0).getint()] greenkey = op.getarglist()[3:] repr = jd_sd.warmstate.get_location_str(greenkey) w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr) - l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op), + l_w.append(DebugMergePoint(space, name, logops.repr_of_resop(op), jd_sd.jitdriver.name, op.getarg(1).getint(), op.getarg(2).getint(), w_greenkey)) else: - l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs, - logops.repr_of_resop(op))) + l_w.append(WrappedOp(name, ofs, logops.repr_of_resop(op))) return l_w + at unwrap_spec(offset=int, repr=str, name=str) +def descr_new_resop(space, w_tp, name, offset=-1, repr=''): + return WrappedOp(name, offset, repr) -class WrappedBox(W_Root): - """ A class representing a single box - """ - def __init__(self, llbox): - self.llbox = llbox - - def descr_getint(self, space): - if not jit_hooks.box_isint(self.llbox): - raise OperationError(space.w_NotImplementedError, - space.wrap("Box has no int value")) - return space.wrap(jit_hooks.box_getint(self.llbox)) - - at unwrap_spec(no=int) -def descr_new_box(space, w_tp, no): - return WrappedBox(jit_hooks.boxint_new(no)) - -WrappedBox.typedef = TypeDef( - 'Box', - __new__ = interp2app(descr_new_box), - getint = interp2app(WrappedBox.descr_getint), -) - - at unwrap_spec(num=int, offset=int, repr=str, w_res=W_Root) -def descr_new_resop(space, w_tp, num, w_args, w_res, offset=-1, - repr=''): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - if space.is_none(w_res): - llres = jit_hooks.emptyval() - else: - if not isinstance(w_res, WrappedBox): - raise OperationError(space.w_TypeError, space.wrap( - "expected box type, got %s" % space.type(w_res))) - llres = w_res.llbox - return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr) - - at unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int) -def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id, + at unwrap_spec(repr=str, name=str, jd_name=str, call_depth=int, call_id=int) +def descr_new_dmp(space, w_tp, name, repr, jd_name, call_depth, call_id, w_greenkey): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - num = rop.DEBUG_MERGE_POINT - return DebugMergePoint(space, - jit_hooks.resop_new(num, args, jit_hooks.emptyval()), + return DebugMergePoint(space, name, repr, jd_name, call_depth, call_id, w_greenkey) class WrappedOp(W_Root): """ A class representing a single ResOperation, wrapped nicely """ - def __init__(self, op, offset, repr_of_resop): - self.op = op + def __init__(self, name, offset, repr_of_resop): self.offset = offset + self.name = name self.repr_of_resop = repr_of_resop def descr_repr(self, space): return space.wrap(self.repr_of_resop) - def descr_num(self, space): - return space.wrap(jit_hooks.resop_getopnum(self.op)) - def descr_name(self, space): - return space.wrap(hlstr(jit_hooks.resop_getopname(self.op))) - - @unwrap_spec(no=int) - def descr_getarg(self, space, no): - try: - box = jit_hooks.resop_getarg(self.op, no) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("Index out of range")) - return WrappedBox(box) - - @unwrap_spec(no=int, w_box=WrappedBox) - def descr_setarg(self, space, no, w_box): - jit_hooks.resop_setarg(self.op, no, w_box.llbox) - - def descr_getresult(self, space): - return WrappedBox(jit_hooks.resop_getresult(self.op)) - - def descr_setresult(self, space, w_box): - box = space.interp_w(WrappedBox, w_box) - jit_hooks.resop_setresult(self.op, box.llbox) + return space.wrap(self.name) class DebugMergePoint(WrappedOp): """ A class representing Debug Merge Point - the entry point to a jitted loop. """ - def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id, - w_greenkey): + def __init__(self, space, name, repr_of_resop, jd_name, call_depth, + call_id, w_greenkey): - WrappedOp.__init__(self, op, -1, repr_of_resop) + WrappedOp.__init__(self, name, -1, repr_of_resop) self.jd_name = jd_name self.call_depth = call_depth self.call_id = call_id @@ -237,12 +165,7 @@ __doc__ = WrappedOp.__doc__, __new__ = interp2app(descr_new_resop), __repr__ = interp2app(WrappedOp.descr_repr), - num = GetSetProperty(WrappedOp.descr_num), name = GetSetProperty(WrappedOp.descr_name), - getarg = interp2app(WrappedOp.descr_getarg), - setarg = interp2app(WrappedOp.descr_setarg), - result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult), offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.typedef.acceptable_as_base_class = False @@ -278,14 +201,18 @@ asmaddr = 0 asmlen = 0 - def __init__(self, space, debug_info, is_bridge=False): - logops = debug_info.logger._make_log_operations() - if debug_info.asminfo is not None: - ofs = debug_info.asminfo.ops_offset + def __init__(self, space, debug_info, is_bridge=False, wrap_ops=True): + if wrap_ops: + memo = {} + logops = debug_info.logger._make_log_operations(memo) + if debug_info.asminfo is not None: + ofs = debug_info.asminfo.ops_offset + else: + ofs = {} + ops = debug_info.operations + self.w_ops = space.newlist(wrap_oplist(space, logops, ops, ofs)) else: - ofs = {} - self.w_ops = space.newlist( - wrap_oplist(space, logops, debug_info.operations, ofs)) + self.w_ops = space.w_None self.jd_name = debug_info.get_jitdriver().name self.type = debug_info.type diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -136,7 +136,6 @@ assert dmp.call_id == 0 assert dmp.offset == -1 assert int_add.name == 'int_add' - assert int_add.num == self.int_add_num assert int_add.offset == 0 self.on_compile_bridge() expected = (' s: + driver.jit_merge_point(i=i, s=s) + i -= 1 + + def main(s): + loop(30, s) + assert jit_hooks.get_jitcell_at_key("jit", s) + assert not jit_hooks.get_jitcell_at_key("jit", s + 1) + jit_hooks.trace_next_iteration("jit", s + 1) + loop(s + 3, s + 1) + assert jit_hooks.get_jitcell_at_key("jit", s + 1) + + self.meta_interp(main, [5]) + self.check_jitcell_token_count(2) + + def test_get_jitcell_at_key_ptr(self): + driver = JitDriver(greens = ['s'], reds = ['i'], name='jit') + + class Green(object): + pass + + def loop(i, s): + while i > 0: + driver.jit_merge_point(i=i, s=s) + i -= 1 + + def main(s): + g1 = Green() + g2 = Green() + g1_ptr = cast_instance_to_gcref(g1) + g2_ptr = cast_instance_to_gcref(g2) + loop(10, g1) + assert jit_hooks.get_jitcell_at_key("jit", g1_ptr) + assert not jit_hooks.get_jitcell_at_key("jit", g2_ptr) + jit_hooks.trace_next_iteration("jit", g2_ptr) + loop(2, g2) + assert jit_hooks.get_jitcell_at_key("jit", g2_ptr) + + self.meta_interp(main, [5]) + self.check_jitcell_token_count(2) + + def test_dont_trace_here(self): + driver = JitDriver(greens = ['s'], reds = ['i', 'k'], name='jit') + + def loop(i, s): + k = 4 + while i > 0: + driver.jit_merge_point(k=k, i=i, s=s) + if s == 1: + loop(3, 0) + k -= 1 + i -= 1 + if k == 0: + k = 4 + driver.can_enter_jit(k=k, i=i, s=s) + + def main(s, check): + if check: + jit_hooks.dont_trace_here("jit", 0) + loop(30, s) + + self.meta_interp(main, [1, 0], inline=True) + self.check_resops(call_assembler_n=0) + self.meta_interp(main, [1, 1], inline=True) + self.check_resops(call_assembler_n=8) + + def test_trace_next_iteration_hash(self): + driver = JitDriver(greens = ['s'], reds = ['i'], name="name") + class Hashes(object): + check = False + + def __init__(self): + self.l = [] + self.t = [] + + hashes = Hashes() + + class Hooks(object): + def before_compile(self, debug_info): + pass + + def after_compile(self, debug_info): + for op in debug_info.operations: + if op.is_guard(): + hashes.l.append(op.getdescr().get_jitcounter_hash()) + + def before_compile_bridge(self, debug_info): + pass + + def after_compile_bridge(self, debug_info): + hashes.t.append(debug_info.fail_descr.get_jitcounter_hash()) + + hooks = Hooks() + + @dont_look_inside + def foo(): + if hashes.l: + for item in hashes.l: + jit_hooks.trace_next_iteration_hash("name", item) + + def loop(i, s): + while i > 0: + driver.jit_merge_point(s=s, i=i) + foo() + if i == 3: + i -= 1 + i -= 1 + + def main(s, check): + hashes.check = check + loop(10, s) + + self.meta_interp(main, [1, 0], policy=JitPolicy(hooks)) + assert len(hashes.l) == 4 + assert len(hashes.t) == 0 + self.meta_interp(main, [1, 1], policy=JitPolicy(hooks)) + assert len(hashes.t) == 1 class LLJitHookInterfaceTests(JitHookInterfaceTests): # use this for any backend, instead of the super class diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -1,9 +1,9 @@ -import sys +import sys, py from rpython.tool.sourcetools import func_with_new_name from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.annlowlevel import (llhelper, MixLevelHelperAnnotator, - cast_base_ptr_to_instance, hlstr) + cast_base_ptr_to_instance, hlstr, cast_instance_to_gcref) from rpython.rtyper.llannotation import lltype_to_annotation from rpython.annotator import model as annmodel from rpython.rtyper.llinterp import LLException @@ -129,6 +129,17 @@ results.append((graph, block, i)) return results +def _find_jit_markers(graphs, marker_names): + results = [] + for graph in graphs: + for block in graph.iterblocks(): + for i in range(len(block.operations)): + op = block.operations[i] + if (op.opname == 'jit_marker' and + op.args[0].value in marker_names): + results.append((graph, block, i)) + return results + def find_can_enter_jit(graphs): return _find_jit_marker(graphs, 'can_enter_jit') @@ -236,6 +247,7 @@ self.rewrite_can_enter_jits() self.rewrite_set_param_and_get_stats() self.rewrite_force_virtual(vrefinfo) + self.rewrite_jitcell_accesses() self.rewrite_force_quasi_immutable() self.add_finish() self.metainterp_sd.finish_setup(self.codewriter) @@ -598,6 +610,80 @@ (_, jd._PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType( [llmemory.GCREF, llmemory.GCREF], ASMRESTYPE) + def rewrite_jitcell_accesses(self): + jitdrivers_by_name = {} + for jd in self.jitdrivers_sd: + name = jd.jitdriver.name + if name != 'jitdriver': + jitdrivers_by_name[name] = jd + m = _find_jit_markers(self.translator.graphs, + ('get_jitcell_at_key', 'trace_next_iteration', + 'dont_trace_here', 'trace_next_iteration_hash')) + accessors = {} + + def get_accessor(name, jitdriver_name, function, ARGS, green_arg_spec): + a = accessors.get((name, jitdriver_name)) + if a: + return a + d = {'function': function, + 'cast_instance_to_gcref': cast_instance_to_gcref, + 'lltype': lltype} + arg_spec = ", ".join([("arg%d" % i) for i in range(len(ARGS))]) + arg_converters = [] + for i, spec in enumerate(green_arg_spec): + if isinstance(spec, lltype.Ptr): + arg_converters.append("arg%d = lltype.cast_opaque_ptr(type%d, arg%d)" % (i, i, i)) + d['type%d' % i] = spec + convert = ";".join(arg_converters) + if name == 'get_jitcell_at_key': + exec py.code.Source(""" + def accessor(%s): + %s + return cast_instance_to_gcref(function(%s)) + """ % (arg_spec, convert, arg_spec)).compile() in d + FUNC = lltype.Ptr(lltype.FuncType(ARGS, llmemory.GCREF)) + elif name == "trace_next_iteration_hash": + exec py.code.Source(""" + def accessor(arg0): + function(arg0) + """).compile() in d + FUNC = lltype.Ptr(lltype.FuncType([lltype.Unsigned], + lltype.Void)) + else: + exec py.code.Source(""" + def accessor(%s): + %s + function(%s) + """ % (arg_spec, convert, arg_spec)).compile() in d + FUNC = lltype.Ptr(lltype.FuncType(ARGS, lltype.Void)) + func = d['accessor'] + ll_ptr = self.helper_func(FUNC, func) + accessors[(name, jitdriver_name)] = ll_ptr + return ll_ptr + + for graph, block, index in m: + op = block.operations[index] + jitdriver_name = op.args[1].value + JitCell = jitdrivers_by_name[jitdriver_name].warmstate.JitCell + ARGS = [x.concretetype for x in op.args[2:]] + if op.args[0].value == 'get_jitcell_at_key': + func = JitCell.get_jitcell + elif op.args[0].value == 'dont_trace_here': + func = JitCell.dont_trace_here + elif op.args[0].value == 'trace_next_iteration_hash': + func = JitCell.trace_next_iteration_hash + else: + func = JitCell._trace_next_iteration + argspec = jitdrivers_by_name[jitdriver_name]._green_args_spec + accessor = get_accessor(op.args[0].value, + jitdriver_name, func, + ARGS, argspec) + v_result = op.result + c_accessor = Constant(accessor, concretetype=lltype.Void) + newop = SpaceOperation('direct_call', [c_accessor] + op.args[2:], + v_result) + block.operations[index] = newop + def rewrite_can_enter_jits(self): sublists = {} for jd in self.jitdrivers_sd: diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -545,12 +545,24 @@ @staticmethod def trace_next_iteration(greenkey): greenargs = unwrap_greenkey(greenkey) + JitCell._trace_next_iteration(*greenargs) + + @staticmethod + def _trace_next_iteration(*greenargs): hash = JitCell.get_uhash(*greenargs) jitcounter.change_current_fraction(hash, 0.98) @staticmethod + def trace_next_iteration_hash(hash): + jitcounter.change_current_fraction(hash, 0.98) + + @staticmethod def ensure_jit_cell_at_key(greenkey): greenargs = unwrap_greenkey(greenkey) + return JitCell._ensure_jit_cell_at_key(*greenargs) + + @staticmethod + def _ensure_jit_cell_at_key(*greenargs): hash = JitCell.get_uhash(*greenargs) cell = jitcounter.lookup_chain(hash) while cell is not None: @@ -561,6 +573,11 @@ newcell = JitCell(*greenargs) jitcounter.install_new_cell(hash, newcell) return newcell + + @staticmethod + def dont_trace_here(*greenargs): + cell = JitCell._ensure_jit_cell_at_key(*greenargs) + cell.flags |= JC_DONT_TRACE_HERE # self.JitCell = JitCell return JitCell diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -5,6 +5,7 @@ cast_base_ptr_to_instance, llstr) from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rtyper.lltypesystem import llmemory, lltype +from rpython.flowspace.model import Constant from rpython.rtyper import rclass @@ -127,3 +128,33 @@ @register_helper(lltype.Ptr(LOOP_RUN_CONTAINER)) def stats_get_loop_run_times(warmrunnerdesc): return warmrunnerdesc.metainterp_sd.cpu.get_all_loop_runs() + +# ---------------------- jitcell interface ---------------------- + +def _new_hook(name, resulttype): + def hook(name, *greenkey): + raise Exception("need to run translated") + hook.func_name = name + + class GetJitCellEntry(ExtRegistryEntry): + _about_ = hook + + def compute_result_annotation(self, s_name, *args_s): + assert s_name.is_constant() + return resulttype + + def specialize_call(self, hop): + c_jitdriver = Constant(hop.args_s[0].const, concretetype=lltype.Void) + c_name = Constant(name, concretetype=lltype.Void) + hop.exception_cannot_occur() + args_v = [hop.inputarg(arg, arg=i + 1) + for i, arg in enumerate(hop.args_r[1:])] + return hop.genop('jit_marker', [c_name, c_jitdriver] + args_v, + resulttype=hop.r_result) + + return hook + +get_jitcell_at_key = _new_hook('get_jitcell_at_key', SomePtr(llmemory.GCREF)) +trace_next_iteration = _new_hook('trace_next_iteration', None) +dont_trace_here = _new_hook('dont_trace_here', None) +trace_next_iteration_hash = _new_hook('trace_next_iteration_hash', None) From noreply at buildbot.pypy.org Sun Sep 20 16:45:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 20 Sep 2015 16:45:43 +0200 (CEST) Subject: [pypy-commit] pypy default: Improve test_redirect_call_assembler to check that it correctly updates Message-ID: <20150920144543.557CE1C120E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79721:13672983edaf Date: 2015-09-20 16:45 +0200 http://bitbucket.org/pypy/pypy/changeset/13672983edaf/ Log: Improve test_redirect_call_assembler to check that it correctly updates the frame_info diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -3789,10 +3789,61 @@ assert called == [finish_descr] del called[:] - # compile a replacement + # compile a replacement which needs more jitframe stack space ops = ''' [f0, f1] f2 = float_sub(f0, f1) + f3 = float_sub(f0, f1) + f4 = float_sub(f0, f1) + f5 = float_sub(f0, f1) + f6 = float_sub(f0, f1) + f7 = float_sub(f0, f1) + f8 = float_sub(f0, f1) + f9 = float_sub(f0, f1) + f10 = float_sub(f0, f1) + f11 = float_sub(f0, f1) + f12 = float_sub(f0, f1) + f13 = float_sub(f0, f1) + f14 = float_sub(f0, f1) + f15 = float_sub(f0, f1) + f16 = float_sub(f0, f1) + f17 = float_sub(f0, f1) + f18 = float_sub(f0, f1) + f19 = float_sub(f0, f1) + i3 = float_eq(f2, f3) + i4 = float_eq(f2, f4) + i5 = float_eq(f2, f5) + i6 = float_eq(f2, f6) + i7 = float_eq(f2, f7) + i8 = float_eq(f2, f8) + i9 = float_eq(f2, f9) + i10 = float_eq(f2, f10) + i11 = float_eq(f2, f11) + i12 = float_eq(f2, f12) + i13 = float_eq(f2, f13) + i14 = float_eq(f2, f14) + i15 = float_eq(f2, f15) + i16 = float_eq(f2, f16) + i17 = float_eq(f2, f17) + i18 = float_eq(f2, f18) + i19 = float_eq(f2, f19) + guard_true(i3) [] + guard_true(i4) [] + guard_true(i5) [] + guard_true(i6) [] + guard_true(i7) [] + guard_true(i8) [] + guard_true(i9) [] + guard_true(i10) [] + guard_true(i11) [] + guard_true(i12) [] + guard_true(i13) [] + guard_true(i14) [] + guard_true(i15) [] + guard_true(i16) [] + guard_true(i17) [] + guard_true(i18) [] + guard_true(i19) [] finish(f2)''' loop2 = parse(ops) looptoken2 = JitCellToken() @@ -3800,9 +3851,19 @@ self.cpu.compile_loop(loop2.inputargs, loop2.operations, looptoken2) finish_descr2 = loop2.operations[-1].getdescr() + # check the jitframeinfo + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 < num2 + # install it self.cpu.redirect_call_assembler(looptoken, looptoken2) + # check that the jitframeinfo was updated + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 == num2 + # now, our call_assembler should go to looptoken2 args = [longlong.getfloatstorage(6.0), longlong.getfloatstorage(1.5)] # 6.0-1.5 == 1.25+3.25 From noreply at buildbot.pypy.org Sun Sep 20 17:14:53 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 20 Sep 2015 17:14:53 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Don't JIT function calling debug_flush() Message-ID: <20150920151453.4EC8C1C0557@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: py3.3 Changeset: r79722:d4201b95691f Date: 2015-09-20 16:12 +0100 http://bitbucket.org/pypy/pypy/changeset/d4201b95691f/ Log: Don't JIT function calling debug_flush() diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -21,7 +21,7 @@ _MACRO_ON_POSIX = True if not _WIN32 else None if _WIN32: - from rpython.rlib import rwin32 + from rpython.rlib import rwin32 from rpython.rlib.rwin32file import make_win32_traits class CConfig: @@ -33,7 +33,7 @@ for _name in """fchdir fchmod fchmodat fchown fchownat fexecve fdopendir fpathconf fstat fstatat fstatvfs ftruncate futimens futimes futimesat linkat lchflags lchmod lchown lstat lutimes - mkdirat mkfifoat mknodat openat readlinkat renameat + mkdirat mkfifoat mknodat openat readlinkat renameat symlinkat unlinkat utimensat""".split(): locals()['HAVE_%s' % _name.upper()] = rffi_platform.Has(_name) cConfig = rffi_platform.configure(CConfig) @@ -376,7 +376,7 @@ @specialize.argtype(0) def _preferred_traits(path): return string_traits - + @specialize.argtype(0, 1) def putenv(name, value): os.environ[_as_bytes(name)] = _as_bytes(value) @@ -469,7 +469,7 @@ if SEEK_SET is not None: if how == 0: how = SEEK_SET - elif how == 1: + elif how == 1: how = SEEK_CUR elif how == 2: how = SEEK_END @@ -891,7 +891,7 @@ c_getlogin = external('getlogin', [], rffi.CCHARP, releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO) -c_getloadavg = external('getloadavg', +c_getloadavg = external('getloadavg', [rffi.CArrayPtr(lltype.Float), rffi.INT], rffi.INT) @replace_os_function('getlogin') @@ -1372,6 +1372,7 @@ return handle_posix_error('killpg', c_killpg(pgrp, sig)) @replace_os_function('_exit') + at jit.dont_look_inside def exit(status): debug.debug_flush() c_exit(status) @@ -1617,7 +1618,7 @@ #___________________________________________________________________ -c_chroot = external('chroot', [rffi.CCHARP], rffi.INT, +c_chroot = external('chroot', [rffi.CCHARP], rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO) @replace_os_function('chroot') From noreply at buildbot.pypy.org Sun Sep 20 18:23:28 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 18:23:28 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: don't share guard_overflow/guard_exception Message-ID: <20150920162328.EF6271C0726@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79723:f2903514ce72 Date: 2015-09-20 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/f2903514ce72/ Log: don't share guard_overflow/guard_exception 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 @@ -573,7 +573,6 @@ self.origin_jitcode = None self.origin_pc = 0 else: - self._really_emitted_operation = None # removed return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields @@ -583,20 +582,7 @@ del self.replaces_guard[orig_op] return else: - guard_op = self.replace_op_with(op, op.getopnum()) - if (self._last_guard_op and guard_op.getdescr() is None and - guard_op.getopnum() != rop.GUARD_VALUE and - not guard_op.same_guard_position(self._last_guard_op)): - op = self._copy_resume_data_from(guard_op, - self._last_guard_op) - else: - op = self.store_final_boxes_in_guard(guard_op, - pendingfields) - self._last_guard_op = op - # for unrolling - for farg in op.getfailargs(): - if farg: - self.force_box(farg) + op = self.emit_guard_operation(op, pendingfields) elif op.can_raise(): self.exception_might_have_happened = True if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): @@ -606,6 +592,24 @@ self._really_emitted_operation = op self._newoperations.append(op) + def emit_guard_operation(self, op, pendingfields): + guard_op = self.replace_op_with(op, op.getopnum()) + if (self._last_guard_op and guard_op.getdescr() is None and + guard_op.getopnum() != rop.GUARD_VALUE and + not guard_op.same_guard_position(self._last_guard_op)): + op = self._copy_resume_data_from(guard_op, + self._last_guard_op) + else: + op = self.store_final_boxes_in_guard(guard_op, pendingfields) + if op.getopnum() not in (rop.GUARD_EXCEPTION, rop.GUARD_OVERFLOW): + self._last_guard_op = op + # for unrolling + for farg in op.getfailargs(): + if farg: + self.force_box(farg) + return op + + def _copy_resume_data_from(self, guard_op, last_guard_op): descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) descr.copy_all_attributes_from(last_guard_op.getdescr()) From noreply at buildbot.pypy.org Sun Sep 20 18:23:31 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 18:23:31 +0200 (CEST) Subject: [pypy-commit] pypy default: add debug prints Message-ID: <20150920162331.42D9E1C0726@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79724:0d51cf599c0e Date: 2015-09-20 18:23 +0200 http://bitbucket.org/pypy/pypy/changeset/0d51cf599c0e/ Log: add debug prints 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 @@ -2905,6 +2905,7 @@ start_stack = [] max_size = 0 max_key = None + debug_start("jit-abort-longest-function") for pair in self.portal_trace_positions: key, pos = pair if key is not None: @@ -2913,14 +2914,18 @@ greenkey, startpos = start_stack.pop() size = pos - startpos if size > max_size: + r = self.jitdriver_sd.warmstate.get_location_str(greenkey) + debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = greenkey if start_stack: key, pos = start_stack[0] size = len(self.history.operations) - pos if size > max_size: + debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = key + debug_stop("jit-abort-longest-function") return max_key def record_result_of_call_pure(self, op): From noreply at buildbot.pypy.org Sun Sep 20 18:40:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 18:40:51 +0200 (CEST) Subject: [pypy-commit] pypy default: oops Message-ID: <20150920164051.1F6611C0403@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79725:4e6f5ed43e2b Date: 2015-09-20 18:40 +0200 http://bitbucket.org/pypy/pypy/changeset/4e6f5ed43e2b/ Log: oops 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 @@ -654,10 +654,10 @@ def is_virtual(self, op): if op.type == 'r': opinfo = self.getptrinfo(op) - return opinfo and opinfo.is_virtual() + return opinfo is not None and opinfo.is_virtual() if op.type == 'i': opinfo = self.getrawptrinfo(op) - return opinfo and opinfo.is_virtual() + return opinfo is not None and opinfo.is_virtual() return False def pure_reverse(self, op): From noreply at buildbot.pypy.org Sun Sep 20 18:46:36 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 18:46:36 +0200 (CEST) Subject: [pypy-commit] pypy default: another oops Message-ID: <20150920164636.451B11C120E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79726:7dfb38c188aa Date: 2015-09-20 18:46 +0200 http://bitbucket.org/pypy/pypy/changeset/7dfb38c188aa/ Log: another oops 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 @@ -2922,6 +2922,7 @@ key, pos = start_stack[0] size = len(self.history.operations) - pos if size > max_size: + r = self.jitdriver_sd.warmstate.get_location_str(greenkey) debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = key From noreply at buildbot.pypy.org Sun Sep 20 18:52:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 18:52:54 +0200 (CEST) Subject: [pypy-commit] pypy default: eh Message-ID: <20150920165254.48E1E1C1DD9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79727:732b5c59e6c9 Date: 2015-09-20 18:52 +0200 http://bitbucket.org/pypy/pypy/changeset/732b5c59e6c9/ Log: eh 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 @@ -2922,7 +2922,7 @@ key, pos = start_stack[0] size = len(self.history.operations) - pos if size > max_size: - r = self.jitdriver_sd.warmstate.get_location_str(greenkey) + r = self.jitdriver_sd.warmstate.get_location_str(key) debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = key From noreply at buildbot.pypy.org Sun Sep 20 19:21:57 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 20 Sep 2015 19:21:57 +0200 (CEST) Subject: [pypy-commit] pypy default: implement some logging Message-ID: <20150920172157.D33161C0726@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79728:261a9cd80920 Date: 2015-09-20 19:22 +0200 http://bitbucket.org/pypy/pypy/changeset/261a9cd80920/ Log: implement some logging diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -82,6 +82,13 @@ debug_stop("jit-log-short-preamble") return logops + def log_abort_loop(self, inputargs, operations, memo=None): + debug_start("jit-abort-log") + logops = self._log_operations(inputargs, operations, ops_offset=None, + memo=memo) + debug_stop("jit-abort-log") + return logops + def _log_operations(self, inputargs, operations, ops_offset, memo=None): if not have_debug_prints(): return None 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 @@ -2926,6 +2926,9 @@ debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = key + self.staticdata.logger_ops.log_abort_loop(self.history.inputargs, + self.history.operations, + self.box_names_memo) debug_stop("jit-abort-longest-function") return max_key From noreply at buildbot.pypy.org Mon Sep 21 08:44:55 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 21 Sep 2015 08:44:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Copy all tests about "no_nul" in strings to test "no_nul" in unicode Message-ID: <20150921064455.C3BA21C01DE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79729:998686594ede Date: 2015-09-21 08:45 +0200 http://bitbucket.org/pypy/pypy/changeset/998686594ede/ Log: Copy all tests about "no_nul" in strings to test "no_nul" in unicode strings. Add a lot of corresponding missing cases in the code. diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -385,7 +385,8 @@ class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeCodePoint)): def union((uchr1, uchr2)): - return SomeUnicodeCodePoint() + no_nul = uchr1.no_nul and uchr2.no_nul + return SomeUnicodeCodePoint(no_nul=no_nul) def add((chr1, chr2)): return SomeUnicodeString() @@ -598,32 +599,33 @@ class __extend__(pairtype(SomeUnicodeString, SomeInteger)): def getitem((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem.can_only_throw = [] def getitem_idx((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem_idx.can_only_throw = [IndexError] def mul((str1, int2)): # xxx do we want to support this - return SomeUnicodeString() + return SomeUnicodeString(no_nul=str1.no_nul) class __extend__(pairtype(SomeInteger, SomeString), pairtype(SomeInteger, SomeUnicodeString)): def mul((int1, str2)): # xxx do we want to support this - return str2.basestringclass() + return str2.basestringclass(no_nul=str2.no_nul) class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeString), pairtype(SomeUnicodeString, SomeUnicodeCodePoint), pairtype(SomeUnicodeString, SomeUnicodeString)): def union((str1, str2)): - return SomeUnicodeString(can_be_None=str1.can_be_none() or - str2.can_be_none()) + can_be_None = str1.can_be_None or str2.can_be_None + no_nul = str1.no_nul and str2.no_nul + return SomeUnicodeString(can_be_None=can_be_None, no_nul=no_nul) def add((str1, str2)): # propagate const-ness to help getattr(obj, 'prefix' + const_name) - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=str1.no_nul and str2.no_nul) if str1.is_immutable_constant() and str2.is_immutable_constant(): result.const = str1.const + str2.const return result diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -237,10 +237,11 @@ else: result = SomeString(no_nul=no_nul) elif tp is unicode: + no_nul = not u'\x00' in x if len(x) == 1: - result = SomeUnicodeCodePoint() + result = SomeUnicodeCodePoint(no_nul=no_nul) else: - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=no_nul) elif tp is bytearray: result = SomeByteArray() elif tp is tuple: diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -438,6 +438,18 @@ assert s.knowntype == str assert s.no_nul + def test_unicode_join(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return [u"foo", u"bar"] + def f(n): + g(0) + return u''.join(g(n)) + s = a.build_types(f, [int]) + assert s.knowntype == unicode + assert s.no_nul + def test_str_split(self): a = self.RPythonAnnotator() def g(n): @@ -451,6 +463,19 @@ s_item = s.listdef.listitem.s_value assert s_item.no_nul + def test_unicode_split(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return u"test string" + def f(n): + if n: + return g(n).split(u' ') + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeList) + s_item = s.listdef.listitem.s_value + assert s_item.no_nul + def test_str_split_nul(self): def f(n): return n.split('\0')[0] @@ -470,6 +495,27 @@ assert not s.can_be_None assert not s.no_nul + def test_unicode_split_nul(self): + def f(n): + return n.split(u'\0')[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert s.no_nul + + def g(n): + return n.split(u'\0', 1)[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(g, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert not s.no_nul + def test_str_splitlines(self): a = self.RPythonAnnotator() def f(a_str): @@ -490,6 +536,18 @@ s = a.build_types(f, [int, annmodel.SomeString(no_nul=True)]) assert s.no_nul + def test_unicode_strip(self): + a = self.RPythonAnnotator() + def f(n, a_str): + if n == 0: + return a_str.strip(u' ') + elif n == 1: + return a_str.rstrip(u' ') + else: + return a_str.lstrip(u' ') + s = a.build_types(f, [int, annmodel.SomeUnicodeString(no_nul=True)]) + assert s.no_nul + def test_str_mul(self): a = self.RPythonAnnotator() def f(a_str): @@ -2042,6 +2100,17 @@ assert s.can_be_None assert s.no_nul + def test_unicode_noNUL_canbeNone(self): + def f(a): + if a: + return u"abc" + else: + return None + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_str_or_None(self): def f(a): if a: @@ -2058,6 +2127,22 @@ assert s.can_be_None assert s.no_nul + def test_unicode_or_None(self): + def f(a): + if a: + return u"abc" + else: + return None + def g(a): + x = f(a) + if x is None: + return u"abcd" + return x + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_emulated_pbc_call_simple(self): def f(a,b): return a + b @@ -2124,6 +2209,19 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_iteritems_unicode0(self): + def it(d): + return d.iteritems() + def f(): + d0 = {u'1a': u'2a', u'3': u'4'} + for item in it(d0): + return u"%s=%s" % item + raise ValueError + a = self.RPythonAnnotator() + s = a.build_types(f, []) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_no_nul_mod(self): def f(x): s = "%d" % x @@ -2133,6 +2231,14 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_no_nul_mod_unicode(self): + def f(x): + s = u"%d" % x + return s + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_mul_str0(self): def f(s): @@ -2142,6 +2248,24 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + + def test_reverse_mul_str0(self): + def f(s): + return 10*s + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeString) + assert s.no_nul + + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_getitem_str0(self): def f(s, n): if n == 1: @@ -2153,12 +2277,18 @@ return s a = self.RPythonAnnotator() a.translator.config.translation.check_str_without_nul = True - s = a.build_types(f, [annmodel.SomeString(no_nul=True), annmodel.SomeInteger()]) assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True), + annmodel.SomeInteger()]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_non_none_and_none_with_isinstance(self): class A(object): pass @@ -3411,6 +3541,7 @@ a = self.RPythonAnnotator() s = a.build_types(f, [unicode]) assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_unicode_char(self): def f(x, i): @@ -3916,6 +4047,19 @@ assert s.can_be_None assert s.no_nul + def test_contains_no_nul_unicode(self): + def f(i): + if u"\0" in i: + return None + else: + return i + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.can_be_None + assert s.no_nul + def test_no___call__(self): class X(object): def __call__(self): From noreply at buildbot.pypy.org Mon Sep 21 09:06:49 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 09:06:49 +0200 (CEST) Subject: [pypy-commit] pypy default: document the branch Message-ID: <20150921070649.E67561C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79730:b4e662c97599 Date: 2015-09-21 09:04 +0200 http://bitbucket.org/pypy/pypy/changeset/b4e662c97599/ Log: document the branch 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 @@ -30,3 +30,6 @@ allocated object. It is controlled by tracking the general progress of these major collection steps and the size of old objects that keep adding up between them. + +.. branch: remember-tracing-counts +Reenable jithooks From noreply at buildbot.pypy.org Mon Sep 21 09:08:25 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 09:08:25 +0200 (CEST) Subject: [pypy-commit] pypy default: arraylen now lands in a different spot Message-ID: <20150921070825.92DCB1C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79731:db28b068daa3 Date: 2015-09-21 09:07 +0200 http://bitbucket.org/pypy/pypy/changeset/db28b068daa3/ Log: arraylen now lands in a different spot diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -422,11 +422,11 @@ i114 = int_ne(i160, i112) guard_false(i114, descr=...) --TICK-- + i123 = arraylen_gc(p67, descr=) i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) setfield_gc(p167, i119, descr=) - i123 = arraylen_gc(p67, descr=) jump(..., descr=...) """) From noreply at buildbot.pypy.org Mon Sep 21 09:12:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 21 Sep 2015 09:12:31 +0200 (CEST) Subject: [pypy-commit] pypy default: the previous "unicode == '\x00'" gives a non-well-defined result Message-ID: <20150921071231.9897C1C13C9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79732:fce28c21dc9b Date: 2015-09-21 09:12 +0200 http://bitbucket.org/pypy/pypy/changeset/fce28c21dc9b/ Log: the previous "unicode == '\x00'" gives a non-well-defined result depending on the host python's default encoding diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -574,7 +574,9 @@ return self.basecharclass() def method_split(self, patt, max=-1): - if max == -1 and patt.is_constant() and patt.const == "\0": + # special-case for .split( '\x00') or .split(u'\x00') + if max == -1 and patt.is_constant() and ( + len(patt.const) == 1 and ord(patt.const) == 0): no_nul = True else: no_nul = self.no_nul From noreply at buildbot.pypy.org Mon Sep 21 09:16:28 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 21 Sep 2015 09:16:28 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip these new parts of the test on llgraph Message-ID: <20150921071628.42DC71C13C9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79733:19e4ec471578 Date: 2015-09-21 09:16 +0200 http://bitbucket.org/pypy/pypy/changeset/19e4ec471578/ Log: Skip these new parts of the test on llgraph diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -3852,17 +3852,19 @@ finish_descr2 = loop2.operations[-1].getdescr() # check the jitframeinfo - num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth - num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth - assert num1 < num2 + if isinstance(self.cpu, AbstractLLCPU): + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 < num2 # install it self.cpu.redirect_call_assembler(looptoken, looptoken2) # check that the jitframeinfo was updated - num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth - num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth - assert num1 == num2 + if isinstance(self.cpu, AbstractLLCPU): + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 == num2 # now, our call_assembler should go to looptoken2 args = [longlong.getfloatstorage(6.0), From noreply at buildbot.pypy.org Mon Sep 21 09:23:35 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 09:23:35 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_pyjitpl Message-ID: <20150921072335.635EF1C13C9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r79734:4772b2299fd8 Date: 2015-09-21 09:23 +0200 http://bitbucket.org/pypy/pypy/changeset/4772b2299fd8/ Log: fix test_pyjitpl 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 @@ -2905,6 +2905,8 @@ start_stack = [] max_size = 0 max_key = None + warmstate = self.jitdriver_sd.warmstate + r = '' debug_start("jit-abort-longest-function") for pair in self.portal_trace_positions: key, pos = pair @@ -2914,7 +2916,8 @@ greenkey, startpos = start_stack.pop() size = pos - startpos if size > max_size: - r = self.jitdriver_sd.warmstate.get_location_str(greenkey) + if warmstate is not None: + r = warmstate.get_location_str(greenkey) debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = greenkey @@ -2922,11 +2925,13 @@ key, pos = start_stack[0] size = len(self.history.operations) - pos if size > max_size: - r = self.jitdriver_sd.warmstate.get_location_str(key) + if warmstate is not None: + r = self.jitdriver_sd.warmstate.get_location_str(key) debug_print("found new longest: %s %d" % (r, size)) max_size = size max_key = key - self.staticdata.logger_ops.log_abort_loop(self.history.inputargs, + if warmstate is not None: # tests + self.staticdata.logger_ops.log_abort_loop(self.history.inputargs, self.history.operations, self.box_names_memo) debug_stop("jit-abort-longest-function") diff --git a/rpython/jit/metainterp/test/test_pyjitpl.py b/rpython/jit/metainterp/test/test_pyjitpl.py --- a/rpython/jit/metainterp/test/test_pyjitpl.py +++ b/rpython/jit/metainterp/test/test_pyjitpl.py @@ -17,6 +17,7 @@ portal.setup(None) class FakeStaticData: cpu = None + warmstate = None warmrunnerdesc = None mainjitcode = portal From noreply at buildbot.pypy.org Mon Sep 21 09:34:28 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 21 Sep 2015 09:34:28 +0200 (CEST) Subject: [pypy-commit] pypy default: Follow-up on a7e480ec1a78, which should have marked this dict and this function as not used any more Message-ID: <20150921073428.59C181C13C9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79735:0389a0369505 Date: 2015-09-21 09:34 +0200 http://bitbucket.org/pypy/pypy/changeset/0389a0369505/ Log: Follow-up on a7e480ec1a78, which should have marked this dict and this function as not used any more diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -92,6 +92,8 @@ if sys.platform == "win32": module_suggests["cpyext"].append(("translation.shared", True)) + +# NOTE: this dictionary is not used any more module_import_dependencies = { # no _rawffi if importing rpython.rlib.clibffi raises ImportError # or CompilationError or py.test.skip.Exception @@ -108,6 +110,7 @@ } def get_module_validator(modname): + # NOTE: this function is not used any more if modname in module_import_dependencies: modlist = module_import_dependencies[modname] def validator(config): From noreply at buildbot.pypy.org Mon Sep 21 10:33:51 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 21 Sep 2015 10:33:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Vague attempt at using a "pypy --translationmodules" to translate: there Message-ID: <20150921083351.48EC01C13C9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79736:32a41767a897 Date: 2015-09-21 10:31 +0200 http://bitbucket.org/pypy/pypy/changeset/32a41767a897/ Log: Vague attempt at using a "pypy --translationmodules" to translate: there is no thread module in the host python then diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py --- a/rpython/rlib/rthread.py +++ b/rpython/rlib/rthread.py @@ -280,7 +280,11 @@ class ThreadLocalField(object): def __init__(self, FIELDTYPE, fieldname, loop_invariant=False): "NOT_RPYTHON: must be prebuilt" - from thread import _local + try: + from thread import _local + except ImportError: + class _local(object): + pass self.FIELDTYPE = FIELDTYPE self.fieldname = fieldname self.local = _local() # <- NOT_RPYTHON From noreply at buildbot.pypy.org Mon Sep 21 11:40:20 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 21 Sep 2015 11:40:20 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: vecopt.py tests passing again, now let's finally head to the assembler Message-ID: <20150921094020.5EF831C01DE@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79737:664117c201a8 Date: 2015-09-21 11:40 +0200 http://bitbucket.org/pypy/pypy/changeset/664117c201a8/ Log: vecopt.py tests passing again, now let's finally head to the assembler diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -91,7 +91,7 @@ guard.setdescr(descr.clone()) guard.setarg(0, box_result) label = loop.find_first(rop.LABEL) - guard.setfailargs(label.getarglist()) + guard.setfailargs(label.getarglist()[:]) opt.emit_operation(guard) return guard @@ -120,7 +120,7 @@ descr = myop.getdescr() descr.copy_all_attributes_from(other.op.getdescr()) myop.rd_frame_info_list = otherop.rd_frame_info_list - myop.setfailargs(otherop.getfailargs()) + myop.setfailargs(otherop.getfailargs()[:]) myop.rd_snapshot = otherop.rd_snapshot def emit_varops(self, opt, var, old_arg): @@ -140,6 +140,7 @@ opt.emit_operation(cmp_op) # emit that actual guard guard = ResOperation(self.op.getopnum(), [cmp_op], self.op.getdescr()) + guard.setfailargs(self.op.getfailargs()[:]) opt.emit_operation(guard) self.setindex(opt.operation_position()-1) self.setoperation(guard) @@ -173,6 +174,7 @@ self.strength_reduced = 0 # how many guards could be removed? self.strongest_guards = {} self.guards = {} + self.delayed = {} def collect_guard_information(self, loop): operations = loop.operations @@ -271,8 +273,30 @@ def emit_operation(self, op): self.renamer.rename(op) + #if op.is_always_pure(): + # self.delay(op) + # return + #self.emit_delayed_for(op) + #if not op.is_always_pure(): self._newoperations.append(op) + def delay(self, op): + self.delayed[op] = None + print "delayed", op + + def emit_delayed_for(self, op): + if op.is_inputarg(): + return + additional = [] + if op.is_guard(): + additional = op.getfailargs() + for arg in op.getarglist() + additional: + if arg in self.delayed: + del self.delayed[arg] + self.emit_delayed_for(arg) + self._newoperations.append(op) + + def operation_position(self): return len(self._newoperations) diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -5,6 +5,7 @@ from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, MemoryRef, Node, IndexVar) from rpython.jit.metainterp.optimizeopt.renamer import Renamer +from rpython.jit.metainterp.resume import AccumInfo from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.jitexc import NotAProfitableLoop from rpython.rlib.objectmodel import specialize, always_inline @@ -23,14 +24,16 @@ def post_schedule(self): loop = self.graph.loop self.renamer.rename(loop.jump) + self.ensure_args_unpacked(loop.jump) loop.operations = self.oplist loop.prefix = self.invariant_oplist - if len(self.invariant_vector_vars) > 0: - # TODO, accum? + if len(self.invariant_vector_vars) + len(self.invariant_oplist) > 0: args = loop.label.getarglist_copy() + self.invariant_vector_vars opnum = loop.label.getopnum() # TODO descr? - loop.prefix_label = loop.label.copy_and_change(opnum, args) + op = loop.label.copy_and_change(opnum, args) + self.renamer.rename(op) + loop.prefix_label = op def profitable(self): return True @@ -172,25 +175,22 @@ def any_size(self): return self.bytesize == TypeRestrict.ANY_SIZE + @always_inline + def any_count(self): + return self.count == TypeRestrict.ANY_COUNT + def check(self, value): assert value.datatype != '\x00' if self.type != TypeRestrict.ANY_TYPE: - if self.type != value.datatype: - assert 0, "type mismatch" - + assert self.type == value.datatype assert value.bytesize > 0 if not self.any_size(): - if self.bytesize != value.bytesize: - assert 0, "size mismatch" - + assert self.bytesize == value.bytesize assert value.count > 0 if self.count != TypeRestrict.ANY_COUNT: - if self.count != value.count: - assert 0, "count mismatch" - + assert value.count >= self.count if self.sign != TypeRestrict.ANY_SIGN: - if bool(self.sign) != value.sign: - assert 0, "sign mismatch" + assert bool(self.sign) == value.sign def max_input_count(self, count): """ How many """ @@ -205,8 +205,7 @@ TR_ANY_INTEGER = TypeRestrict(INT) TR_FLOAT_2 = TypeRestrict(FLOAT, 4, 2) TR_DOUBLE_2 = TypeRestrict(FLOAT, 8, 2) - TR_LONG = TypeRestrict(INT, 8, 2) - TR_INT_2 = TypeRestrict(INT, 4, 2) + TR_INT32_2 = TypeRestrict(INT, 4, 2) # note that the following definition is x86 arch specific MAPPING = { @@ -237,9 +236,10 @@ rop.VEC_INT_SIGNEXT: [TR_ANY_INTEGER], rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: [TR_DOUBLE_2], - rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: [TR_FLOAT_2], + # weird but the trace will store single floats in int boxes + rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: [TR_INT32_2], rop.VEC_CAST_FLOAT_TO_INT: [TR_DOUBLE_2], - rop.VEC_CAST_INT_TO_FLOAT: [TR_INT_2], + rop.VEC_CAST_INT_TO_FLOAT: [TR_INT32_2], rop.VEC_FLOAT_EQ: [TR_ANY_FLOAT,TR_ANY_FLOAT], rop.VEC_FLOAT_NE: [TR_ANY_FLOAT,TR_ANY_FLOAT], @@ -264,11 +264,6 @@ assert isinstance(vecop, GuardResOp) vecop.setfailargs(op.getfailargs()) vecop.rd_snapshot = op.rd_snapshot - if pack.is_accumulating(): - for i,node in enumerate(pack.operations): - op = node.getoperation() - state.accumulation[op] = pack - def prepare_arguments(state, pack, args): # Transforming one argument to a vector box argument @@ -344,6 +339,12 @@ @always_inline def position_values(state, restrict, pack, args, index, position): + arg = args[index] + newcount, count = restrict.count, arg.count + if not restrict.any_count() and newcount != count: + if position == 0: + pass + pass if position != 0: # The vector box is at a position != 0 but it # is required to be at position 0. Unpack it! @@ -527,18 +528,17 @@ #self.appendedvar_pos_arg_count = len(sched_data.invariant_vector_vars) failargs = op.getfailargs() descr = op.getdescr() + # note: stitching a guard must resemble the order of the label + # otherwise a wrong mapping is handed to the register allocator for i,arg in enumerate(failargs): if arg is None: continue accum = self.accumulation.get(arg, None) if accum: assert isinstance(accum, AccumPack) - accum.attach_accum_info(descr.rd_accum_list, i) - - def post_schedule(self): - loop = self.graph.loop - self.ensure_args_unpacked(loop.jump) - SchedulerState.post_schedule(self) + accum.attach_accum_info(descr, i, arg) + seed = accum.getseed() + failargs[i] = self.renamer.rename_map.get(seed, seed) def profitable(self): return self.costmodel.profitable() @@ -602,6 +602,8 @@ if var: if var in self.invariant_vector_vars: return arg + if arg in self.accumulation: + return var args = [var, ConstInt(pos), ConstInt(1)] vecop = OpHelpers.create_vec_unpack(var.type, args, var.bytesize, var.signed, 1) @@ -757,12 +759,12 @@ vector register. """ before_count = len(packlist) - #print "splitting pack", self + print "splitting pack", self pack = self while pack.pack_load(vec_reg_size) > Pack.FULL: pack.clear() oplist, newoplist = pack.slice_operations(vec_reg_size) - #print " split of %dx, left: %d" % (len(oplist), len(newoplist)) + print " split of %dx, left: %d" % (len(oplist), len(newoplist)) pack.operations = oplist pack.update_pack_of_nodes() if not pack.leftmost().is_typecast(): @@ -778,7 +780,7 @@ newpack.clear() newpack.operations = [] break - #print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) + print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): @@ -864,9 +866,8 @@ return 0 def attach_accum_info(self, descr, position, scalar): - descr.rd_accum_list = AccumInfo(descr.rd_accum_list, - position, self.operator, - self.scalar, None) + descr.rd_accum_list = AccumInfo(descr.rd_accum_list, position, self.operator, + scalar, None) def is_accumulating(self): return True diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -1085,7 +1085,7 @@ f2 = float_add(f0, f1) i1 = int_add(i0, 8) i2 = int_lt(i1, 100) - guard_false(i2) [p0, i0, f2] + guard_true(i2) [p0, i0, f2] jump(p0, i1, f2) """ trace_opt = """ @@ -1094,9 +1094,11 @@ v7[2xf64] = vec_int_xor(v6[0xf64], v6[0xf64]) v2[2xf64] = vec_pack_f(v7[2xf64], f0, 0, 1) label(p0, i0, v2[2xf64]) + i100 = int_add(i0, 8) + i200 = int_lt(i100, 100) i1 = int_add(i0, 16) i2 = int_lt(i1, 100) - guard_false(i2) [p0, i0, v2[2xf64]] + guard_true(i2) [p0, i0, v2[2xf64]] i10 = int_add(i0, 16) i20 = int_lt(i10, 100) v1[2xf64] = vec_raw_load_f(p0, i0, descr=floatarraydescr) @@ -1108,7 +1110,7 @@ self.assert_equal(loop, self.parse_loop(trace_opt)) def test_element_f45_in_guard_failargs(self): - ops = """ + trace = self.parse_loop(""" [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] f45 = raw_load_f(i21, i44, descr=floatarraydescr) guard_not_invalidated() [p38, p12, p9, p14, f45, p39, i37, i44, f35, i40, p42, i43, None, i28, p36, i41] @@ -1122,33 +1124,33 @@ i52 = int_ge(i50, i18) guard_false(i52) [p38, p12, p9, p14, i48, i46, f47, i51, i50, f45, p39, None, None, None, i40, p42, i43, None, None, p36, None] jump(p36, i50, p9, i51, p14, f45, p12, p38, f47, p39, i40, i48, p42, i43, i46, i21, i4, i0, i18) - """ - opt = """ + """) + trace_opt = self.parse_loop(""" [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] - guard_not_invalidated() [p38, p12, p9, p14, p39, i37, i44, f35, i40, p42, i43, f34, i28, p36, i41] + guard_not_invalidated() [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] i50 = int_add(i28, 1) - i48 = int_add(i41, 8) - i51 = int_add(i37, 8) - i54 = int_add(i41, 16) - i46 = int_add(i44, 8) - i56 = int_add(i37, 16) - i52 = int_ge(i50, i18) - i637 = int_add(i28, 2) - i638 = int_ge(i637, i18) + i20 = int_ge(i50, i18) + i54 = int_add(i28, 2) + i638 = int_ge(i54, i18) guard_false(i638) [p36, i28, p9, i37, p14, f34, p12, p38, f35, p39, i40, i41, p42, i43, i44, i21, i4, i0, i18] + i12 = int_add(i44, 8) + i56 = int_add(i41, 8) + i46 = int_add(i37, 8) + i47 = int_add(i28, 2) + i52 = int_ge(i47, i18) i55 = int_add(i44, 16) - i629 = int_add(i28, 2) - i57 = int_ge(i637, i18) - v61 = vec_raw_load_f(i21, i44, 2, descr=floatarraydescr) - v62 = vec_raw_load_f(i4, i41, 2, descr=floatarraydescr) - v63 = vec_float_add(v61, v62) + i629 = int_add(i41, 16) + i637 = int_add(i37, 16) + v61[2xf64] = vec_raw_load_f(i21, i44, descr=floatarraydescr) + v62[2xf64] = vec_raw_load_f(i4, i41, descr=floatarraydescr) + v63[2xf64] = vec_float_add(v61, v62) vec_raw_store(i0, i37, v63, descr=floatarraydescr) - f100 = vec_float_unpack(v61, 1, 1) - f101 = vec_float_unpack(v62, 1, 1) + f100 = vec_unpack_f(v61, 1, 1) + f101 = vec_unpack_f(v62, 1, 1) jump(p36, i637, p9, i56, p14, f100, p12, p38, f101, p39, i40, i54, p42, i43, i55, i21, i4, i0, i18) - """ - vopt = self.vectorize(self.parse_loop(ops)) - self.assert_equal(vopt.loop, self.parse_loop(opt)) + """) + vopt = self.vectorize(trace) + self.assert_equal(trace, trace_opt) def test_shrink_vector_size(self): ops = """ @@ -1187,7 +1189,7 @@ self.assert_equal(loop, self.parse_loop(opt)) def test_castup_arith_castdown(self): - ops = """ + trace = self.parse_loop(""" [p0,p1,p2,i0,i4] i10 = raw_load_i(p0, i0, descr=float32arraydescr) i1 = int_add(i0, 4) @@ -1201,76 +1203,57 @@ i186 = int_lt(i5, 100) guard_true(i186) [] jump(p0,p1,p2,i1,i5) - """ - opt = """ + """) + trace_opt = self.parse_loop(""" [p0, p1, p2, i0, i4] i5 = int_add(i4, 4) - i1 = int_add(i0, 4) i186 = int_lt(i5, 100) i500 = int_add(i4, 16) i501 = int_lt(i500, 100) guard_true(i501) [p0, p1, p2, i0, i4] - i189 = int_add(i0, 8) + i189 = int_add(i0, 4) i187 = int_add(i4, 8) - i198 = int_add(i0, 12) i188 = int_lt(i187, 100) - i207 = int_add(i0, 16) + i207 = int_add(i0, 8) i196 = int_add(i4, 12) i197 = int_lt(i196, 100) - i205 = int_add(i4, 16) - i206 = int_lt(i205, 100) - v228 = vec_raw_load_i(p0, i0, 4, descr=float32arraydescr) - v229 = vec_cast_singlefloat_to_float(v228) - v230 = vec_int_unpack(v228, 2, 2) + i205 = int_add(i0, 12) + i400 = int_add(i4, 16) + i401= int_lt(i400, 100) + i402 = int_add(i0, 16) + v228[4xi32] = vec_raw_load_i(p0, i0, descr=float32arraydescr) + v229[2xf64] = vec_cast_singlefloat_to_float(v228) + v230 = vec_unpack_i(v228, 2, 2) v231 = vec_cast_singlefloat_to_float(v230) - v232 = vec_raw_load_i(p1, i1, 4, descr=float32arraydescr) + v232 = vec_raw_load_i(p1, i189, descr=float32arraydescr) v233 = vec_cast_singlefloat_to_float(v232) - v234 = vec_int_unpack(v232, 2, 2) + v236 = vec_float_add(v229, v233) + v238 = vec_cast_float_to_singlefloat(v236) + v234 = vec_unpack_i(v232, 2, 2) v235 = vec_cast_singlefloat_to_float(v234) v237 = vec_float_add(v231, v235) v239 = vec_cast_float_to_singlefloat(v237) - v236 = vec_float_add(v229, v233) - v238 = vec_cast_float_to_singlefloat(v236) - v240 = vec_pack_f(v238, v239, 2, 2) + v240 = vec_pack_i(v238, v239, 2, 2) vec_raw_store(p2, i4, v240, descr=float32arraydescr) jump(p0, p1, p2, i207, i500) - """ - vopt = self.vectorize(self.parse_loop(ops)) - self.assert_equal(vopt.loop, self.parse_loop(opt)) - - def test_truediv_abs_neg_float(self): - ops = """ - [f9,p10,i11,p4,i12,p2,p5,p13,i14,p7,i15,p8,i16,f17,i18,i19] - f20 = raw_load(i16, i12, descr=floatarraydescr) - guard_not_invalidated() [p8, p7, p5, p4, p2, f20, None, i12, i11, p10, i15, i14, p13] - i23 = int_add(i12, 8) - f24 = float_truediv(f20, f17) - f25 = float_abs(f20) - f26 = float_neg(f20) - raw_store(i18, i15, f24, descr=floatarraydescr) - i26 = int_add(i14, 1) - i28 = int_add(i15, 8) - i29 = int_ge(i26, i19) - guard_false(i29) [p8, p7, p5, p4, p2, f20, i23, i28, None, p13] - jump(f20, p10, i11, p4, i23, p2, p5, p13, i26, p7, i28, p8, i16, f17, i18, i19) - """ - opt = self.vectorize(self.parse_loop(ops)) - self.debug_print_operations(opt.loop) + """) + vopt = self.vectorize(trace) + self.assert_equal(trace, trace_opt) def test_axis_sum(self): trace = """ [i1, p10, i11, p8, i12, p3, p4, p13, i14, i15, p6, p9, i16, i17, i18, i19, i20, i21, i22, i23] - f24 = raw_load(i16, i12, descr=floatarraydescr) + f24 = raw_load_f(i16, i12, descr=floatarraydescr) guard_not_invalidated() [i1, p9, p8, p6, p4, p3, f24, i11, i15, p13, i12, i14, p10] i26 = int_add(i12, 8) - i27 = getarrayitem_gc(p13, i1, descr=floatarraydescr) + i27 = getarrayitem_gc_f(p13, i1, descr=floatarraydescr) i28 = int_is_zero(i27) guard_false(i28) [i1, p9, p8, p6, p4, p3, f24, i26, i11, i15, p13, None, i14, p10] - f30 = raw_load(i17, i15, descr=floatarraydescr) + f30 = raw_load_f(i17, i15, descr=floatarraydescr) f31 = float_add(f30, f24) raw_store(i18, i15, f31, descr=floatarraydescr) i33 = int_add(i14, 1) - i34 = getarrayitem_gc(p13, i19, descr=floatarraydescr) + i34 = getarrayitem_gc_f(p13, i19, descr=floatarraydescr) i35 = int_lt(i34, i20) guard_true(i35) [i1, p9, p8, p6, p4, p3, i21, i34, i15, i33, i19, p13, f31, None, i26, i11, None, None, None, i14, p10] i37 = int_add(i34, 1) @@ -1287,7 +1270,8 @@ pass def test_cast_1(self): - trace = """ + # TODO + trace = self.parse_loop(""" [i9, i10, p2, p11, i12, i13, p4, p5, p14, i15, p8, i16, p17, i18, i19, i20, i21, i22, i23] i24 = raw_load_i(i20, i16, descr=float32arraydescr) guard_not_invalidated() [p8, p5, p4, p2, i24, p17, i13, i12, i10, i19, p14, p11, i18, i15, i16, None] @@ -1304,11 +1288,33 @@ i39 = int_ge(i36, i23) guard_false(i39) [p8, p5, p4, p2, i27, i28, i30, i24, i38, i36, p17, None, None, None, None, p14, p11, i18, i15, None, None] jump(i24, i28, p2, p11, i36, i38, p4, p5, p14, i15, p8, i27, p17, i18, i30, i20, i21, i22, i23) - """ - opt = self.vectorize(self.parse_loop(trace)) - self.debug_print_operations(opt.loop) + """) + opt = self.vectorize(trace) + self.debug_print_operations(trace) + + def test_truediv_abs_neg_float(self): + # TODO + trace = self.parse_loop(""" + [f9,p10,i11,p4,i12,p2,p5,p13,i14,p7,i15,p8,i16,f17,i18,i19] + f20 = raw_load_f(i16, i12, descr=floatarraydescr) + guard_not_invalidated() [p8, p7, p5, p4, p2, f20, None, i12, i11, p10, i15, i14, p13] + i23 = int_add(i12, 8) + f24 = float_truediv(f20, f17) + f25 = float_abs(f20) + f26 = float_neg(f20) + raw_store(i18, i15, f24, descr=floatarraydescr) + i26 = int_add(i14, 1) + i28 = int_add(i15, 8) + i29 = int_ge(i26, i19) + guard_false(i29) [p8, p7, p5, p4, p2, f20, i23, i28, None, p13] + jump(f20, p10, i11, p4, i23, p2, p5, p13, i26, p7, i28, p8, i16, f17, i18, i19) + """) + opt = self.vectorize(trace) + self.debug_print_operations(trace) + def test_all_guard(self): + # TODO trace = """ [p0, p3, i4, i5, i6, i7] f8 = raw_load_f(i6, i5, descr=floatarraydescr) @@ -1327,6 +1333,7 @@ self.debug_print_operations(loop) def test_max(self): + # TODO trace = """ [p3, i4, p2, i5, f6, i7, i8] f9 = raw_load_f(i7, i5, descr=floatarraydescr) 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 @@ -148,6 +148,7 @@ x = op1.getarg(i) y = op2.getarg(i) assert x.same_box(remap.get(y, y)) + assert x.same_shape(remap.get(y, y)) if op2 in remap: assert op1.same_box(remap[op2]) else: diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -36,7 +36,7 @@ class VectorLoop(object): def __init__(self, label, oplist, jump): self.label = label - self.inputargs = label.getarglist() + self.inputargs = label.getarglist_copy() self.prefix = [] self.prefix_label = None assert self.label.getopnum() == rop.LABEL @@ -160,15 +160,6 @@ self.has_two_labels = False def propagate_all_forward(self, info, loop): - #label = loop.label - #jump = loop.jump - #if jump.getopnum() not in (rop.LABEL, rop.JUMP) or \ - # label.getopnum() != rop.LABEL: - # import pdb; pdb. set_trace() - # raise NotAVectorizeableLoop() - #if jump.numargs() != label.numargs(): - # import pdb; pdb. set_trace() - # raise NotAVectorizeableLoop() self.orig_label_args = loop.label.getarglist_copy() self.linear_find_smallest_type(loop) byte_count = self.smallest_type_bytes @@ -207,29 +198,6 @@ def unroll_loop_iterations(self, loop, unroll_count): """ Unroll the loop X times. unroll_count + 1 = unroll_factor """ numops = len(loop.operations) - # use the target token of the label - #target_token = label_op.getdescr() - #if not we_are_translated(): - # target_token.assumed_classes = {} - #if jump_op.getopnum() == rop.LABEL: - # jump_op = ResOperation(rop.JUMP, jump_op.getarglist(), target_token) - #else: - # jump_op = jump_op.clone() - # jump_op.setdescr(target_token) - #assert jump_op.is_final() - - #self.emit_unrolled_operation(label_op) - - #for i in range(0,numops): - # op = loop.operations[i].copy() - # if op.is_guard(): - # assert isinstance(op, GuardResOp) - # failargs = renamer.rename_failargs(op, clone=True) - # snapshot = renamer.rename_rd_snapshot(op.rd_snapshot, clone=True) - # op.setfailargs(failargs) - # op.rd_snapshot = snapshot - # operations.append(op) - # self.emit_unrolled_operation(op) renamer = Renamer() operations = loop.operations @@ -560,16 +528,12 @@ """ Marks this guard as an early exit! """ op = node.getoperation() assert isinstance(op, GuardResOp) - descr = None if op.getopnum() in (rop.GUARD_TRUE, rop.GUARD_FALSE): descr = CompileLoopVersionDescr() - else: - descr = ResumeAtLoopHeaderDescr() - if op.getdescr(): - descr.copy_all_attributes_from(op.getdescr()) - # - op.setdescr(descr) - op.setfailargs(loop.inputargs) + if op.getdescr(): + descr.copy_all_attributes_from(op.getdescr()) + op.setdescr(descr) + op.setfailargs(loop.label.getarglist_copy()) class CostModel(object): """ Utility to estimate the savings for the new trace loop. @@ -789,6 +753,9 @@ for pack in self.packs: if not pack.is_accumulating(): continue + for i,node in enumerate(pack.operations): + op = node.getoperation() + state.accumulation[op] = pack assert isinstance(pack, AccumPack) datatype = pack.getdatatype() bytesize = pack.getbytesize() @@ -818,6 +785,7 @@ state.setvector_of_box(pack.getseed(), 0, vecop) # prevent it from expansion state.renamer.start_renaming(pack.getseed(), vecop) + def split_overloaded_packs(self): newpacks = [] for i,pack in enumerate(self.packs): diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -28,9 +28,6 @@ else: self.descrs.append(descr) self.leads_to[descr] = version - # note: stitching a guard must resemble the order of the label - # otherwise a wrong mapping is handed to the register allocator - op.setfailargs(version.renamed_inputargs) assert version.renamed_inputargs is not None def remove(self, descr): diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -37,7 +37,7 @@ return self is other def same_shape(self, other): - return self is other + return True def repr_short(self, memo): return self.repr(memo) From noreply at buildbot.pypy.org Mon Sep 21 15:13:39 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 21 Sep 2015 15:13:39 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: guard.py tests passing again Message-ID: <20150921131339.64FC61C01DE@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79738:275b9b40d178 Date: 2015-09-21 14:59 +0200 http://bitbucket.org/pypy/pypy/changeset/275b9b40d178/ Log: guard.py tests passing again diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -82,16 +82,14 @@ opnum = self.transitive_cmpop(self.cmp_op.getopnum()) box_rhs = self.emit_varops(opt, self.rhs, self.cmp_op.getarg(1)) other_rhs = self.emit_varops(opt, other.rhs, other.cmp_op.getarg(1)) - box_result = self.cmp_op.result.clonebox() - opt.emit_operation(ResOperation(opnum, [box_rhs, other_rhs], box_result)) + compare = ResOperation(opnum, [box_rhs, other_rhs]) + opt.emit_operation(compare) # guard - guard = self.op.clone() - descr = guard.getdescr() + descr = CompileLoopVersionDescr() + descr.copy_all_attributes_from(self.op.getdescr()) assert isinstance(descr, ResumeGuardDescr) - guard.setdescr(descr.clone()) - guard.setarg(0, box_result) - label = loop.find_first(rop.LABEL) - guard.setfailargs(label.getarglist()[:]) + guard = ResOperation(self.op.getopnum(), [compare], descr=descr) + guard.setfailargs(loop.label.getarglist_copy()) opt.emit_operation(guard) return guard @@ -146,12 +144,12 @@ self.setoperation(guard) self.setcmp(cmp_op) - def set_to_none(self, loop): + def set_to_none(self, info, loop): operations = loop.operations assert operations[self.index] is self.op operations[self.index] = None descr = self.op.getdescr() - loop.version_info.remove(descr) + # TODO loop.version_info.remove(descr) #if descr and descr.loop_version(): # assert isinstance(descr, CompileLoopVersionDescr) # descr.version = None @@ -280,21 +278,22 @@ #if not op.is_always_pure(): self._newoperations.append(op) - def delay(self, op): - self.delayed[op] = None - print "delayed", op + # delay the pure ops + #def delay(self, op): + # self.delayed[op] = None + # print "delayed", op - def emit_delayed_for(self, op): - if op.is_inputarg(): - return - additional = [] - if op.is_guard(): - additional = op.getfailargs() - for arg in op.getarglist() + additional: - if arg in self.delayed: - del self.delayed[arg] - self.emit_delayed_for(arg) - self._newoperations.append(op) + #def emit_delayed_for(self, op): + # if op.is_inputarg(): + # return + # additional = [] + # if op.is_guard(): + # additional = op.getfailargs() + # for arg in op.getarglist() + additional: + # if arg in self.delayed: + # del self.delayed[arg] + # self.emit_delayed_for(arg) + # self._newoperations.append(op) def operation_position(self): @@ -315,18 +314,21 @@ transitive_guard = one.transitive_imply(other, self, loop) if transitive_guard: if version is None: - version = loop.snapshot() - other.set_to_none(loop) + version = info.snapshot(loop) + other.set_to_none(info, loop) descr = transitive_guard.getdescr() assert isinstance(descr, ResumeGuardDescr) info.track(transitive_guard, descr, version) info.clear() - if self.has_two_labels: - oplist = [loop.operations[0]] + self._newoperations + \ - [op for op in loop.operations[1:] if op] - loop.operations = oplist - else: - loop.operations = self._newoperations + \ - [op for op in loop.operations if op] + loop.prefix += self._newoperations + loop.operations = [op for op in loop.operations if op] + # TODO if self.has_two_labels: + # TODO oplist = [loop.operations[0]] + self._newoperations + \ + # TODO [op for op in loop.operations[1:] if op] + # TODO loop.operations = oplist + # TODO else: + # TODO loop.operations = self._newoperations + \ + # TODO [op for op in loop.operations if op] + diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -36,11 +36,12 @@ def build_dependency(self, ops): loop = self.parse_loop(ops) - self.last_graph = DependencyGraph(loop) - self.show_dot_graph(self.last_graph, self.test_name) - for node in self.last_graph.nodes: + graph = DependencyGraph(loop) + self.show_dot_graph(graph, self.test_name) + for node in graph.nodes: assert node.independent(node) - return self.last_graph + graph.parsestr = ops + return graph def parse_loop(self, ops, add_label=True): loop = self.parse(ops, postprocess=self.postprocess) @@ -116,12 +117,11 @@ "dependencies unexpected %s.\n%s" \ % (dependencies,graph) - def assert_dependencies(self, ops, full_check=True): - graph = self.build_dependency(ops) + def assert_dependencies(self, graph, full_check=True): import re deps = {} exceptions = {} - for i,line in enumerate(ops.splitlines()): + for i,line in enumerate(graph.parsestr.splitlines()): dep_pattern = re.compile("#\s*(\d+):") dep_match = dep_pattern.search(line) if dep_match: @@ -142,18 +142,18 @@ self.assert_edges(graph, edges, exceptions) return graph - def assert_independent(self, a, b): + def assert_independent(self, graph, a, b): a -= 1 b -= 1 - a = self.last_graph.getnode(a) - b = self.last_graph.getnode(b) + a = graph.getnode(a) + b = graph.getnode(b) assert a.independent(b), "{a} and {b} are dependent!".format(a=a,b=b) - def assert_dependent(self, a, b): + def assert_dependent(self, graph, a, b): a -= 1 b -= 1 - a = self.last_graph.getnode(a) - b = self.last_graph.getnode(b) + a = graph.getnode(a) + b = graph.getnode(b) assert not a.independent(b), "{a} and {b} are independent!".format(a=a,b=b) def show_dot_graph(self, graph, name): @@ -237,82 +237,82 @@ assert m1.alias(m2) == alias def test_dependency_empty(self): - ops = """ + graph = self.build_dependency(""" [] # 0: 1 jump() # 1: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_dependency_of_constant_not_used(self): - ops = """ + graph = self.build_dependency(""" [] # 0: 2 i1 = int_add(1,1) # 1: 2 jump() # 2: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_dependency_simple(self): - ops = """ + graph = self.build_dependency(""" [] # 0: 4 i1 = int_add(1,1) # 1: 2 i2 = int_add(i1,1) # 2: 3 guard_value(i2,3) [] # 3: 4 jump() # 4: - """ - graph = self.assert_dependencies(ops, full_check=True) + """) + graph = self.assert_dependencies(graph, full_check=True) self.assert_dependent(graph, 1,2) self.assert_dependent(graph, 2,3) self.assert_dependent(graph, 1,3) def test_def_use_jump_use_def(self): - ops = """ + graph = self.build_dependency(""" [i3] # 0: 1 i1 = int_add(i3,1) # 1: 2, 3 guard_value(i1,0) [] # 2: 3 jump(i1) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_dependency_guard(self): - ops = """ + graph = self.build_dependency(""" [i3] # 0: 2,3 i1 = int_add(1,1) # 1: 2 guard_value(i1,0) [i3] # 2: 3 jump(i3) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_dependency_guard_2(self): - ops = """ + graph = self.build_dependency(""" [i1] # 0: 1,2?,3 i2 = int_le(i1, 10) # 1: 2 guard_true(i2) [i1] # 2: i3 = int_add(i1,1) # 3: 4 jump(i3) # 4: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_no_edge_duplication(self): - ops = """ + graph = self.build_dependency(""" [i1] # 0: 1,2?,3 i2 = int_lt(i1,10) # 1: 2 guard_false(i2) [i1] # 2: i3 = int_add(i1,i1) # 3: 4 jump(i3) # 4: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_no_edge_duplication_in_guard_failargs(self): - ops = """ + graph = self.build_dependency(""" [i1] # 0: 1,2?,3? i2 = int_lt(i1,10) # 1: 2 guard_false(i2) [i1,i1,i2,i1,i2,i1] # 2: 3 jump(i1) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_dependencies_1(self): - ops=""" + graph = self.build_dependency(""" [i0, i1, i2] # 0: 1,3,6,7,11? i4 = int_gt(i1, 0) # 1: 2 guard_true(i4) [] # 2: 5, 11? @@ -325,62 +325,62 @@ i16 = int_gt(i12, 0) # 9: 10 guard_true(i16) [] # 10: 11 jump(i12, i1, i14) # 11: - """ - self.assert_dependencies(ops, full_check=True) - self.assert_independent(6, 2) - self.assert_independent(6, 1) + """) + self.assert_dependencies(graph, full_check=True) + self.assert_independent(graph, 6, 2) + self.assert_independent(graph, 6, 1) def test_prevent_double_arg(self): - ops=""" + graph = self.build_dependency(""" [i0, i1, i2] # 0: 1,3 i4 = int_gt(i1, i0) # 1: 2 guard_true(i4) [] # 2: 3 jump(i0, i1, i2) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_ovf_dep(self): - ops=""" + graph = self.build_dependency(""" [i0, i1, i2] # 0: 2,3 i4 = int_sub_ovf(1, 0) # 1: 2 guard_overflow() [i2] # 2: 3 jump(i0, i1, i2) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_exception_dep(self): - ops=""" + graph = self.build_dependency(""" [p0, i1, i2] # 0: 1,3? i4 = call_i(p0, 1, descr=nonwritedescr) # 1: 2,3 guard_no_exception() [] # 2: 3 jump(p0, i1, i2) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_call_dependency_on_ptr_but_not_index_value(self): - ops=""" + graph = self.build_dependency(""" [p0, p1, i2] # 0: 1,2?,3?,4?,5? i3 = int_add(i2,1) # 1: 2 i4 = call_i(p0, i3, descr=nonwritedescr) # 2: 3,4,5? guard_no_exception() [i2] # 3: p2 = getarrayitem_gc_r(p1, i3, descr=arraydescr) # 4: 5 jump(p2, p1, i3) # 5: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_call_dependency(self): - ops=""" + graph = self.build_dependency(""" [p0, p1, i2, i5] # 0: 1,2?,3?,4?,5? i3 = int_add(i2,1) # 1: 2 i4 = call_i(i5, i3, descr=nonwritedescr) # 2: 3,4,5? guard_no_exception() [i2] # 3: 5? p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 4: 5 jump(p2, p1, i3, i5) # 5: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_call_not_forced_exception(self): - ops=""" + graph = self.build_dependency(""" [p0, p1, i2, i5] # 0: 1,2,4?,5,6 i4 = call_i(i5, i2, descr=nonwritedescr) # 1: 2,4,6 guard_not_forced() [i2] # 2: 3 @@ -388,47 +388,47 @@ i3 = int_add(i2,1) # 4: 5 p2 = getarrayitem_gc_r(p1,i3,descr=chararraydescr) # 5: 6 jump(p2, p1, i2, i5) # 6: - """ - self.assert_dependencies(ops, full_check=True) - assert self.last_graph.nodes[1].priority == 100 - assert self.last_graph.nodes[2].priority == 100 + """) + self.assert_dependencies(graph, full_check=True) + assert graph.nodes[1].priority == 100 + assert graph.nodes[2].priority == 100 def test_setarrayitem_dependency(self): - ops=""" + graph = self.build_dependency(""" [p0, i1] # 0: 1,2?,3?,4? setarrayitem_raw(p0, i1, 1, descr=floatarraydescr) # 1: 2,3 i2 = getarrayitem_raw_i(p0, i1, descr=floatarraydescr) # 2: 4 setarrayitem_raw(p0, i1, 2, descr=floatarraydescr) # 3: 4 jump(p0, i2) # 4: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_setarrayitem_alias_dependency(self): # #1 depends on #2, i1 and i2 might alias, reordering would destroy # coorectness - ops=""" + graph = self.build_dependency(""" [p0, i1, i2] # 0: 1,2?,3? setarrayitem_raw(p0, i1, 1, descr=floatarraydescr) # 1: 2 setarrayitem_raw(p0, i2, 2, descr=floatarraydescr) # 2: 3 jump(p0, i1, i2) # 3: - """ - self.assert_dependencies(ops, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) self.assert_dependent(graph, 1,2) def test_setarrayitem_dont_depend_with_memref_info(self): - ops=""" + graph = self.build_dependency(""" [p0, i1] # 0: 1,2,3?,4? setarrayitem_raw(p0, i1, 1, descr=chararraydescr) # 1: 4 i2 = int_add(i1,1) # 2: 3 setarrayitem_raw(p0, i2, 2, descr=chararraydescr) # 3: 4 jump(p0, i1) # 4: - """ - self.assert_dependencies(ops, full_check=True) - self.assert_independent(1,2) - self.assert_independent(1,3) # they modify 2 different cells + """) + self.assert_dependencies(graph, full_check=True) + self.assert_independent(graph, 1,2) + self.assert_independent(graph, 1,3) # they modify 2 different cells def test_dependency_complex_trace(self): - ops = """ + graph = self.build_dependency(""" [i0, i1, i2, i3, i4, i5, i6, i7] # 0: 1,2,3,4,6,7,8,9,10,12,14,17,19,20,21 i9 = int_mul(i0, 8) # 1: 2 i10 = raw_load_i(i3, i9, descr=arraydescr) # 2: 5, 10 @@ -451,33 +451,32 @@ i25 = int_lt(i24, i7) # 19: guard_true(i25) [i7, i22, i5, i4, i3, i21, i19, i24] # 20: jump(i24, i19, i21, i3, i4, i5, i22, i7) # 21: - """ - self.assert_dependencies(ops, full_check=False) + """) + self.assert_dependencies(graph, full_check=False) self.assert_dependent(graph, 2,12) def test_getfield(self): - trace = """ + graph = self.build_dependency(""" [p0, p1] # 0: 1,2,5 p2 = getfield_gc_r(p0) # 1: 3,5 p3 = getfield_gc_r(p0) # 2: 4 guard_nonnull(p2) [p2] # 3: 4,5 guard_nonnull(p3) [p3] # 4: 5 jump(p0,p2) # 5: - """ - self.assert_dependencies(trace, full_check=True) + """) + self.assert_dependencies(graph, full_check=True) def test_cyclic(self): - trace = """ + graph = self.build_dependency(""" [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6 - guard_early_exit() [] # 1: - p13 = getfield_gc_r(p9) # 2: 3,5,6 - guard_nonnull(p13) [] # 3: 5,6 - i14 = getfield_gc_i(p9) # 4: 6 - p15 = getfield_gc_r(p13) # 5: 6 - guard_class(p15, 140737326900656) [p1, p0, p9, i14, p15, p13, p5, p6, p7] # 6: 7 - jump(p0,p1,p5,p6,p7,p9,p11,p12) # 7: - """ - self.assert_dependencies(trace, full_check=True) + p13 = getfield_gc_r(p9) # 1: 2,4,5 + guard_nonnull(p13) [] # 2: 4,5 + i14 = getfield_gc_i(p9) # 3: 5 + p15 = getfield_gc_r(p13) # 4: 5 + guard_class(p15, 140737326900656) [p1, p0, p9, i14, p15, p13, p5, p6, p7] # 5: 6 + jump(p0,p1,p5,p6,p7,p9,p11,p12) # 6: + """) + self.assert_dependencies(graph, full_check=True) def test_iterate(self): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_guard.py b/rpython/jit/metainterp/optimizeopt/test/test_guard.py --- a/rpython/jit/metainterp/optimizeopt/test/test_guard.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_guard.py @@ -13,8 +13,9 @@ from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.metainterp.optimizeopt.test.test_schedule import SchedulerBaseTest from rpython.jit.metainterp.optimizeopt.test.test_vecopt import (FakeMetaInterpStaticData, - FakeJitDriverStaticData) -from rpython.jit.metainterp.resoperation import rop, ResOperation + FakeJitDriverStaticData, FakeLoopInfo) +from rpython.jit.metainterp.resoperation import (rop, + ResOperation, InputArgInt) from rpython.jit.tool.oparser_model import get_model class FakeMemoryRef(object): @@ -36,7 +37,7 @@ class FakeOp(object): def __init__(self, cmpop): - self.boolinverse = ResOperation(cmpop, [None, None], None).boolinverse + self.boolinverse = ResOperation(cmpop, [box(0), box(0)], None).boolinverse self.cmpop = cmpop def getopnum(self): @@ -80,19 +81,19 @@ class GuardBaseTest(SchedulerBaseTest): def optguards(self, loop, user_code=False): - #loop.snapshot() + info = FakeLoopInfo(loop) + info.snapshot(loop) for op in loop.operations: if op.is_guard(): op.setdescr(compile.CompileLoopVersionDescr()) dep = DependencyGraph(loop) - opt = GuardStrengthenOpt(dep.index_vars, False) - xxx - opt.propagate_all_forward(loop, user_code) + opt = GuardStrengthenOpt(dep.index_vars) + opt.propagate_all_forward(info, loop, user_code) return opt def assert_guard_count(self, loop, count): guard = 0 - for op in loop.operations: + for op in loop.operations + loop.prefix: if op.is_guard(): guard += 1 if guard != count: @@ -106,7 +107,8 @@ def __repr__(self): return '*' from rpython.jit.tool.oparser import OpParser, default_fail_descr - parser = OpParser(instr, self.cpu, self.namespace(), 'lltype', None, default_fail_descr, True, None) + parser = OpParser(instr, self.cpu, self.namespace, 'lltype', None, default_fail_descr, False, None) + parser.vars = { arg.repr_short(arg._repr_memo) : arg for arg in loop.inputargs} operations = [] last_glob = None prev_op = None @@ -125,8 +127,6 @@ last_glob.next = op last_glob = None operations.append(op) - prev_op = op - def check(op, candidate, rename): m = 0 if isinstance(candidate, Glob): @@ -144,14 +144,15 @@ else: rename[arg] = oarg - if op.result: - rename[op.result] = candidate.result + if not op.returns_void(): + rename[op] = candidate m += 1 return m return 0 j = 0 rename = {} - for i, op in enumerate(loop.operations): + ops = loop.finaloplist() + for i, op in enumerate(ops): candidate = operations[j] j += check(op, candidate, rename) if isinstance(operations[-1], Glob): @@ -322,10 +323,10 @@ self.assert_guard_count(loop1, 2) self.assert_contains_sequence(loop1, """ ... - i10 = int_gt(i1, 42) + i10 = int_ge(42, i2) guard_true(i10) [] ... - i40 = int_gt(i11, i2) + i40 = int_gt(i1, 42) guard_true(i40) [] ... """) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -47,6 +47,14 @@ def operation_list(self): return [self.label] + self.operations + [self.jump] + def finaloplist(self): + oplist = [] + if self.prefix_label: + oplist = [self.prefix_label] + self.prefix + elif self.prefix: + oplist = self.prefix + return oplist + self.operations + [self.jump] + def assemble_oplist(self): oplist = self.prefix + [self.prefix_label] + \ loop.operations + [loop.jump] diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -39,7 +39,9 @@ def get(self, descr): return self.leads_to.get(descr, None) - def snapshot(self, operations, label): + def snapshot(self, loop): + operations = loop.finaloplist() + label = loop.label oplist = [] ignore = (rop.DEBUG_MERGE_POINT,) for op in operations: diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -699,7 +699,7 @@ def same_shape(self, other): """ NOT_RPYTHON """ - if not other.is_vector(): + if other.is_vector() != self.is_vector(): return False if self.datatype != other.datatype: return False From noreply at buildbot.pypy.org Mon Sep 21 15:13:41 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 21 Sep 2015 15:13:41 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: datatype is not set if input does not define a datatype Message-ID: <20150921131341.BEE921C01DE@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79739:bcfb21ad79c8 Date: 2015-09-21 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/bcfb21ad79c8/ Log: datatype is not set if input does not define a datatype diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -146,12 +146,14 @@ while arg.is_constant() and i+1 < self.numargs(): i += 1 arg = self.getarg(i) - if arg.is_constant(): + if arg.is_constant() or arg.datatype == '\x00': if arg.type == 'i': self.setdatatype('i', INT_WORD, True) + elif arg.type == 'f': + self.setdatatype('f', FLOAT_WORD, False) else: - assert arg.type == 'f' - self.setdatatype('f', FLOAT_WORD, False) + assert arg.type == 'r' + self.setdatatype('r', INT_WORD, False) return self.setdatatype(arg.datatype, arg.bytesize, arg.signed) assert self.datatype != '\x00' From noreply at buildbot.pypy.org Mon Sep 21 17:23:26 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 17:23:26 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: checkin in-progress Message-ID: <20150921152326.BF1EF1C1379@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79741:070844031819 Date: 2015-09-21 17:22 +0200 http://bitbucket.org/pypy/pypy/changeset/070844031819/ Log: checkin in-progress 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 @@ -1503,7 +1503,8 @@ elif opnum == rop.GUARD_NO_OVERFLOW: # Produced by int_xxx_ovf(). The pc is just after the opcode. # We get here because it did not used to overflow, but now it does. - return get_llexception(self.cpu, OverflowError()) + #return get_llexception(self.cpu, OverflowError()) + pass # elif opnum == rop.GUARD_OVERFLOW: # Produced by int_xxx_ovf(). The pc is just after the opcode. 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 @@ -567,13 +567,15 @@ self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if op.is_guard(): assert isinstance(op, GuardResOp) - if self.origin_jitcode is not None: - if (self.origin_jitcode is op.rd_frame_info_list.jitcode and - self.origin_pc is op.rd_frame_info_list.pc): - self.origin_jitcode = None - self.origin_pc = 0 - else: - return # we optimize the guard + #if self.origin_jitcode is not None: + # if (self.origin_jitcode is op.rd_frame_info_list.jitcode and + # self.origin_pc is op.rd_frame_info_list.pc): + # self.origin_jitcode = None + # self.origin_pc = 0 + # else: + # import pdb + # pdb.set_trace() + # return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None @@ -595,14 +597,13 @@ def emit_guard_operation(self, op, pendingfields): guard_op = self.replace_op_with(op, op.getopnum()) if (self._last_guard_op and guard_op.getdescr() is None and - guard_op.getopnum() != rop.GUARD_VALUE and - not guard_op.same_guard_position(self._last_guard_op)): + guard_op.getopnum() != rop.GUARD_VALUE): op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) - if op.getopnum() not in (rop.GUARD_EXCEPTION, rop.GUARD_OVERFLOW): - self._last_guard_op = op + #if op.getopnum() not in (rop.GUARD_EXCEPTION, rop.GUARD_OVERFLOW): + self._last_guard_op = op # for unrolling for farg in op.getfailargs(): if farg: 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 @@ -230,13 +230,13 @@ for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']: exec py.code.Source(''' - @arguments("box", "box") - def opimpl_%s(self, b1, b2): + @arguments("box", "box", "orgpc") + def opimpl_%s(self, b1, b2, orgpc): self.metainterp.clear_exception() resbox = self.execute(rop.%s, b1, b2) self.make_result_of_lastop(resbox) # same as execute_varargs() if not isinstance(resbox, Const): - self.metainterp.handle_possible_overflow_error() + self.metainterp.handle_possible_overflow_error(orgpc) return resbox ''' % (_opimpl, _opimpl.upper())).compile() @@ -418,7 +418,7 @@ assert box.getint() == 0 target = switchdict.dict[const1.getint()] self.metainterp.generate_guard(rop.GUARD_FALSE, box, - resumepc=target) + resumepc=orgpc) else: # found one of the cases self.implement_guard_value(valuebox, orgpc) @@ -2480,11 +2480,12 @@ pass # XXX we want to do something special in resume descr, # but not now elif opnum == rop.GUARD_NO_OVERFLOW: # an overflow now detected - self.execute_raised(OverflowError(), constant=True) - try: - self.finishframe_exception() - except ChangeFrame: - pass + pass + #self.execute_raised(OverflowError(), constant=True) + #try: + # self.finishframe_exception() + #except ChangeFrame: + # pass elif opnum == rop.GUARD_OVERFLOW: # no longer overflowing self.clear_exception() else: @@ -2772,9 +2773,9 @@ else: self.generate_guard(rop.GUARD_NO_EXCEPTION, None, []) - def handle_possible_overflow_error(self): + def handle_possible_overflow_error(self, orgpc): if self.last_exc_value: - op = self.generate_guard(rop.GUARD_OVERFLOW, None) + op = self.generate_guard(rop.GUARD_OVERFLOW, None, resumepc=orgpc) op.setref_base(lltype.cast_opaque_ptr(llmemory.GCREF, self.last_exc_value)) assert self.class_of_last_exc_is_const @@ -2782,7 +2783,7 @@ lltype.cast_opaque_ptr(llmemory.GCREF, self.last_exc_value)) self.finishframe_exception() else: - self.generate_guard(rop.GUARD_NO_OVERFLOW, None) + self.generate_guard(rop.GUARD_NO_OVERFLOW, None, resumepc=orgpc) def assert_no_exception(self): assert not self.last_exc_value diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -378,12 +378,6 @@ newop.rd_frame_info_list = self.rd_frame_info_list return newop - def same_guard_position(self, other): - assert isinstance(other, GuardResOp) - frame_info1 = self.rd_frame_info_list - frame_info2 = other.rd_frame_info_list - return (frame_info1.jitcode is frame_info2.jitcode and - frame_info1.pc == frame_info2.pc) # =========== # type mixins 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 @@ -723,6 +723,7 @@ elif n == 7: a = 3 else: a = 2 x = intmask(x * 10 + a) + #print "XXXXXXXXXXXXXXXX", x i += 1 return x res = self.meta_interp(f, [0], backendopt=True) @@ -1866,7 +1867,8 @@ res = self.meta_interp(g, [6, 20]) assert res == g(6, 20) self.check_trace_count(8) - self.check_resops(getarrayitem_gc_i=10) + # 6 extra from sharing guard data + self.check_resops(getarrayitem_gc_i=10 + 6) def test_multiple_specialied_versions_bridge(self): myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res']) @@ -2055,8 +2057,8 @@ res = self.meta_interp(g, [3, 23]) assert res == 7068153 self.check_trace_count(6) - self.check_resops(guard_true=6, guard_class=2, int_mul=3, - int_add=3, guard_false=3) + self.check_resops(guard_true=8, guard_class=2, int_mul=3, + int_add=3, guard_false=4) def test_dont_trace_every_iteration(self): myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa']) @@ -2079,7 +2081,7 @@ self.check_enter_count(2) def test_current_trace_length(self): - myjitdriver = JitDriver(greens = ['g'], reds = ['x']) + myjitdriver = JitDriver(greens = ['g'], reds = ['x', 'l']) @dont_look_inside def residual(): print "hi there" @@ -2090,14 +2092,15 @@ residual() y += 1 def f(x, g): + l = [] n = 0 while x > 0: - myjitdriver.can_enter_jit(x=x, g=g) - myjitdriver.jit_merge_point(x=x, g=g) + myjitdriver.can_enter_jit(x=x, g=g, l=l) + myjitdriver.jit_merge_point(x=x, g=g, l=l) loop(g) x -= 1 - n = current_trace_length() - return n + l.append(current_trace_length()) + return l[-2] # not the blackholed version res = self.meta_interp(f, [5, 8]) assert 14 < res < 42 res = self.meta_interp(f, [5, 2]) @@ -2638,7 +2641,7 @@ i += 1 return sa assert self.meta_interp(f, [20]) == f(20) - self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=2) + self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=4) def test_intbounds_not_generalized1(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa']) @@ -2655,7 +2658,7 @@ i += 1 return sa assert self.meta_interp(f, [20]) == f(20) - self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3) + self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=5) def test_intbounds_not_generalized2(self): @@ -2676,7 +2679,7 @@ i += 1 return sa assert self.meta_interp(f, [20]) == f(20) - self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=2) + self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=4) def test_retrace_limit1(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a']) From noreply at buildbot.pypy.org Mon Sep 21 17:23:24 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 17:23:24 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix regalloc tests Message-ID: <20150921152324.868A81C1373@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79740:24f279c53d00 Date: 2015-09-21 17:22 +0200 http://bitbucket.org/pypy/pypy/changeset/24f279c53d00/ Log: fix regalloc tests 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 @@ -76,11 +76,11 @@ assert jitcode.num_regs_i() == 2 assert jitcode.num_regs_r() == 0 assert jitcode.num_regs_f() == 0 - assert jitcode._live_vars(5) == '%i0 %i1' + assert jitcode._live_vars(0) == '%i0 %i1' # from rpython.jit.codewriter.jitcode import MissingLiveness for i in range(len(jitcode.code)+1): - if i != 5: + if i != 0: py.test.raises(MissingLiveness, jitcode._live_vars, i) def test_call(): diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py --- a/rpython/jit/codewriter/test/test_flatten.py +++ b/rpython/jit/codewriter/test/test_flatten.py @@ -169,8 +169,8 @@ return n + 1 self.encoding_test(f, [10], """ int_gt %i0, $0 -> %i1 + -live- goto_if_not %i1, L1 - -live- L1 int_copy %i0 -> %i2 int_sub %i2, $3 -> %i3 int_copy %i3 -> %i4 @@ -194,8 +194,8 @@ int_copy %i1 -> %i3 L1: int_gt %i2, $0 -> %i4 + -live- goto_if_not %i4, L2 - -live- L2 int_copy %i2 -> %i5 int_copy %i3 -> %i6 int_add %i6, %i5 -> %i7 @@ -218,8 +218,8 @@ int_copy %i0 -> %i2 int_copy %i1 -> %i3 L1: + -live- goto_if_not_int_gt %i2, $0, L2 - -live- L2 int_copy %i2 -> %i4 int_copy %i3 -> %i5 int_add %i5, %i4 -> %i6 @@ -457,8 +457,8 @@ # note that 'goto_if_not_int_is_true' is not the same thing # as just 'goto_if_not', because the last one expects a boolean self.encoding_test(f, [7], """ + -live- goto_if_not_int_is_true %i0, L1 - -live- L1 int_return $False --- L1: @@ -523,8 +523,8 @@ else: return m2 self.encoding_test(f, [4, 5, 6], """ + -live- %i0, %i1, %i2 goto_if_not_int_is_true %i0, L1 - -live- %i1, %i2, L1 int_return %i1 --- L1: diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -187,7 +187,7 @@ res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [sp1, sp2] - assert block.exitswitch == ('int_gt', v1, v2) + assert block.exitswitch == ('int_gt', v1, v2, '-live-before') assert block.exits == exits def test_optimize_goto_if_not__incoming(): @@ -211,7 +211,7 @@ res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] - assert block.exitswitch == ('int_gt', v1, v2) + assert block.exitswitch == ('int_gt', v1, v2, '-live-before') assert block.exits == exits assert exits[1].args == [const(True)] @@ -235,7 +235,7 @@ res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] - assert block.exitswitch == (opname, v1, v2) + assert block.exitswitch == (opname, v1, v2, '-live-before') assert block.exits == exits def test_optimize_goto_if_not__ptr_iszero(): diff --git a/rpython/jit/codewriter/test/test_regalloc.py b/rpython/jit/codewriter/test/test_regalloc.py --- a/rpython/jit/codewriter/test/test_regalloc.py +++ b/rpython/jit/codewriter/test/test_regalloc.py @@ -63,8 +63,8 @@ self.check_assembler(graph, """ L1: int_gt %i0, $0 -> %i2 + -live- goto_if_not %i2, L2 - -live- L2 int_add %i1, %i0 -> %i1 int_sub %i0, $1 -> %i0 goto L1 @@ -82,8 +82,8 @@ self.check_assembler(graph, """ L1: int_gt %i0, $0 -> %i2 + -live- goto_if_not %i2, L2 - -live- L2 int_push %i1 int_copy %i0 -> %i1 int_pop -> %i0 @@ -102,8 +102,8 @@ self.check_assembler(graph, """ L1: int_gt %i0, $0 -> %i0 + -live- goto_if_not %i0, L2 - -live- L2 int_copy %i1 -> %i0 int_copy $2 -> %i1 goto L1 @@ -121,8 +121,8 @@ self.check_assembler(graph, """ L1: int_gt %i0, $0 -> %i3 + -live- goto_if_not %i3, L2 - -live- L2 int_push %i1 int_copy %i2 -> %i1 int_copy %i0 -> %i2 @@ -142,8 +142,8 @@ self.check_assembler(graph, """ L1: int_gt %i0, $0 -> %i3 + -live- goto_if_not %i3, L2 - -live- L2 int_copy %i2 -> %i1 goto L1 --- @@ -236,8 +236,8 @@ self.check_assembler(graph, """ int_lshift %i0, %i1 -> %i2 int_rshift %i2, %i1 -> %i1 + -live- goto_if_not_int_ne %i1, %i0, L1 - -live- L1 raise $<* struct object> --- L1: From noreply at buildbot.pypy.org Mon Sep 21 20:02:24 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 21 Sep 2015 20:02:24 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: all optimizeopt tests pass again Message-ID: <20150921180224.D71941C13DD@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79742:abfd8bc5e489 Date: 2015-09-21 20:02 +0200 http://bitbucket.org/pypy/pypy/changeset/abfd8bc5e489/ Log: all optimizeopt tests pass again 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 @@ -120,7 +120,7 @@ return self.all_fielddescrs def is_object(self): - self.S = S + return self._is_object def get_vtable(self): assert self._vtable is not None 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 @@ -158,6 +158,8 @@ continue if 'FLOAT' in op: continue + if 'VEC' in op: + continue args = [] for _ in range(oparity[opnum]): args.append(random.randrange(1, 20)) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -143,7 +143,7 @@ def schedule(self, loop, unroll_factor = -1, with_guard_opt=False): info = FakeLoopInfo(loop) - info.snapshot(loop.operations + [loop.jump], loop.label) + info.snapshot(loop) opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.find_adjacent_memory_refs(graph) opt.extend_packset() @@ -158,7 +158,7 @@ def vectorize(self, loop, unroll_factor = -1): info = FakeLoopInfo(loop) - info.snapshot(loop.operations + [loop.jump], loop.label) + info.snapshot(loop) opt, graph = self.vectoroptimizer_unrolled(loop, unroll_factor) opt.find_adjacent_memory_refs(graph) opt.extend_packset() @@ -671,7 +671,7 @@ """ loop = self.parse_loop(ops) vopt, graph = self.init_packset(loop,1) - self.assert_independent(4,8) + self.assert_independent(graph, 4,8) assert vopt.packset is not None assert len(graph.memory_refs) == 2 assert len(vopt.packset.packs) == 1 @@ -699,7 +699,7 @@ for i in range(3): x = (i+1)*2 y = x + 2 - self.assert_independent(x,y) + self.assert_independent(graph, x,y) self.assert_packset_contains_pair(vopt.packset, x,y) def test_packset_init_2(self): @@ -732,7 +732,7 @@ for i in range(15): x = (i+1)*4 y = x + 4 - self.assert_independent(x,y) + self.assert_independent(graph, x,y) self.assert_packset_contains_pair(vopt.packset, x, y) def test_isomorphic_operations(self): @@ -766,7 +766,7 @@ loop = self.parse_loop(ops) vopt, graph = self.extend_packset(loop,1) assert len(graph.memory_refs) == 2 - self.assert_independent(5,10) + self.assert_independent(graph, 5,10) assert len(vopt.packset.packs) == 2 self.assert_packset_empty(vopt.packset, len(loop.operations), @@ -786,9 +786,9 @@ loop = self.parse_loop(ops) vopt, graph = self.extend_packset(loop,1) assert len(graph.memory_refs) == 4 - self.assert_independent(4,10) - self.assert_independent(5,11) - self.assert_independent(6,12) + self.assert_independent(graph, 4,10) + self.assert_independent(graph, 5,11) + self.assert_independent(graph, 6,12) assert len(vopt.packset.packs) == 3 self.assert_packset_empty(vopt.packset, len(loop.operations), [(6,12), (5,11), (4,10)]) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -133,7 +133,10 @@ elif self.opnum == rop.INT_SIGNEXT: arg0 = self.getarg(0) arg1 = self.getarg(1) - self.setdatatype('i', arg1.value, arg0.signed) + signed = True + if not arg0.is_constant(): + signed = arg0.signed + self.setdatatype('i', arg1.value, True) elif self.is_typecast(): ft,tt = self.cast_types() self.setdatatype(tt, self.cast_to_bytesize(), tt == 'i') From noreply at buildbot.pypy.org Mon Sep 21 20:05:18 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 20:05:18 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fight a bit with overflows, codewriter level Message-ID: <20150921180518.A8B8D1C13DD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79743:42f7b1bd660b Date: 2015-09-21 19:59 +0200 http://bitbucket.org/pypy/pypy/changeset/42f7b1bd660b/ Log: fight a bit with overflows, codewriter level diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py --- a/rpython/jit/codewriter/flatten.py +++ b/rpython/jit/codewriter/flatten.py @@ -1,4 +1,4 @@ -from rpython.flowspace.model import Variable, Constant +from rpython.flowspace.model import Variable, Constant, c_last_exception from rpython.jit.metainterp.history import AbstractDescr, getkind from rpython.rtyper.lltypesystem import lltype @@ -114,6 +114,12 @@ # operations = block.operations for i, op in enumerate(operations): + if '_ovf' in op.opname: + if (len(block.exits) != 2 or + block.exitswitch is not c_last_exception): + raise Exception("detected a block containing ovfcheck()" + " but no OverflowError is caught, this" + " is not legal in jitted blocks") self.serialize_op(op) # self.insert_exits(block) @@ -171,11 +177,24 @@ # An exception block. See test_exc_exitswitch in test_flatten.py # for an example of what kind of code this makes. index = -1 - while True: - lastopname = block.operations[index].opname - if lastopname != '-live-': - break - index -= 1 + opname = block.operations[index].opname + if '_ovf' in opname: + # ovf checking operation as a lat thing, -live- should be + # one before it + line = self.popline() + self.emitline(opname[:7] + '_jump_if_ovf', + TLabel(block.exits[1]), *line[1:]) + assert len(block.exits) == 2 + self.make_link(block.exits[0]) + self.emitline(Label(block.exits[1])) + self.make_exception_link(block.exits[1]) + return + else: + while True: + lastopname = block.operations[index].opname + if lastopname != '-live-': + break + index -= 1 assert block.exits[0].exitcase is None # is this always True? # if not self._include_all_exc_links: @@ -189,10 +208,7 @@ self.make_link(block.exits[0]) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: - if (link.exitcase is Exception or - (link.exitcase is OverflowError and - lastopname.startswith('int_') and - lastopname.endswith('_ovf'))): + if link.exitcase is Exception: # this link captures all exceptions self.make_exception_link(link) break @@ -320,6 +336,9 @@ def emitline(self, *line): self.ssarepr.insns.append(line) + def popline(self): + return self.ssarepr.insns.pop() + def flatten_list(self, arglist): args = [] for v in arglist: 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 @@ -8,7 +8,8 @@ from rpython.jit.metainterp.history import getkind from rpython.jit.metainterp.typesystem import deref, arrayItem from rpython.jit.metainterp.blackhole import BlackholeInterpreter -from rpython.flowspace.model import SpaceOperation, Variable, Constant +from rpython.flowspace.model import SpaceOperation, Variable, Constant,\ + c_last_exception from rpython.rlib import objectmodel from rpython.rlib.jit import _we_are_jitted from rpython.rlib.rgc import lltype_is_gc @@ -333,13 +334,13 @@ def rewrite_op_int_add_ovf(self, op): op0 = self._rewrite_symmetric(op) op1 = SpaceOperation('-live-', [], None) - return [op0, op1] + return [op1, op0] rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf def rewrite_op_int_sub_ovf(self, op): op1 = SpaceOperation('-live-', [], None) - return [op, op1] + return [op1, op] def _noop_rewrite(self, op): return op diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py --- a/rpython/jit/codewriter/test/test_flatten.py +++ b/rpython/jit/codewriter/test/test_flatten.py @@ -538,15 +538,44 @@ except OverflowError: return 42 self.encoding_test(f, [7, 2], """ - int_add_ovf %i0, %i1 -> %i2 - -live- %i2 - catch_exception L1 + -live- %i0, %i1 + int_add_jump_if_ovf L1, %i0, %i1 -> %i2 int_return %i2 --- L1: int_return $42 """, transform=True, liveness=True) + def test_multiple_int_add_ovf(self): + def f(i, j): + try: + ovfcheck(j + i) + return ovfcheck(i + j) + except OverflowError: + return 42 + self.encoding_test(f, [7, 2], """ + -live- %i0, %i1 + int_add_jump_if_ovf L1, %i1, %i0 -> %i2 + int_copy %i1 -> %i3 + int_copy %i0 -> %i4 + -live- %i3, %i4 + int_add_jump_if_ovf L2, %i4, %i3 -> %i5 + int_return %i5 + --- + L2: + int_return $42 + --- + L1: + int_return $42 + """, transform=True, liveness=True) + + def test_ovfcheck_no_catch(self): + def f(i, j): + return ovfcheck(i + j) + err = py.test.raises(Exception, "self.encoding_test(f, [7, 2], ''," + "transform=True, liveness=True)") + assert "ovfcheck()" in str(err) + def test_residual_call_raising(self): @dont_look_inside def g(i, j): diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -15,7 +15,7 @@ for prod in result: yield tuple(prod) -from rpython.flowspace.model import FunctionGraph, Block, Link +from rpython.flowspace.model import FunctionGraph, Block, Link, c_last_exception from rpython.flowspace.model import SpaceOperation, Variable, Constant from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi from rpython.rtyper import rclass @@ -287,7 +287,7 @@ for v2 in [varoftype(lltype.Signed), const(43)]: op = SpaceOperation('int_add_nonneg_ovf', [v1, v2], v3) oplist = Transformer(FakeCPU()).rewrite_operation(op) - op0, op1 = oplist + op1, op0 = oplist assert op0.opname == 'int_add_ovf' if isinstance(v1, Constant) and isinstance(v2, Variable): assert op0.args == [v2, v1] From noreply at buildbot.pypy.org Mon Sep 21 20:53:52 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 20:53:52 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: one more case Message-ID: <20150921185353.039611C1379@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79744:51f2f9c26591 Date: 2015-09-21 20:54 +0200 http://bitbucket.org/pypy/pypy/changeset/51f2f9c26591/ Log: one more case diff --git a/rpython/jit/codewriter/codewriter.py b/rpython/jit/codewriter/codewriter.py --- a/rpython/jit/codewriter/codewriter.py +++ b/rpython/jit/codewriter/codewriter.py @@ -48,7 +48,7 @@ # which means mostly producing a linear list of operations and # inserting jumps or conditional jumps. This is a list of tuples # of the shape ("opname", arg1, ..., argN) or (Label(...),). - ssarepr = flatten_graph(graph, regallocs) + ssarepr = flatten_graph(graph, regallocs, cpu=self.callcontrol.cpu) # # step 3b: compute the liveness around certain operations compute_liveness(ssarepr) diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py --- a/rpython/jit/codewriter/flatten.py +++ b/rpython/jit/codewriter/flatten.py @@ -60,10 +60,11 @@ # ____________________________________________________________ -def flatten_graph(graph, regallocs, _include_all_exc_links=False): +def flatten_graph(graph, regallocs, _include_all_exc_links=False, + cpu=None): """Flatten the graph into an SSARepr, with already-computed register allocations. 'regallocs' in a dict {kind: RegAlloc}.""" - flattener = GraphFlattener(graph, regallocs, _include_all_exc_links) + flattener = GraphFlattener(graph, regallocs, _include_all_exc_links, cpu) flattener.enforce_input_args() flattener.generate_ssa_form() return flattener.ssarepr @@ -71,9 +72,11 @@ class GraphFlattener(object): - def __init__(self, graph, regallocs, _include_all_exc_links=False): + def __init__(self, graph, regallocs, _include_all_exc_links=False, + cpu=None): self.graph = graph self.regallocs = regallocs + self.cpu = cpu self._include_all_exc_links = _include_all_exc_links self.registers = {} if graph: @@ -100,7 +103,7 @@ self.seen_blocks = {} self.make_bytecode_block(self.graph.startblock) - def make_bytecode_block(self, block): + def make_bytecode_block(self, block, handling_ovf=False): if block.exits == (): self.make_return(block.inputargs) return @@ -122,7 +125,7 @@ " is not legal in jitted blocks") self.serialize_op(op) # - self.insert_exits(block) + self.insert_exits(block, handling_ovf) def make_return(self, args): if len(args) == 1: @@ -142,16 +145,16 @@ raise Exception("?") self.emitline("---") - def make_link(self, link): + def make_link(self, link, handling_ovf): if (link.target.exits == () and link.last_exception not in link.args and link.last_exc_value not in link.args): self.make_return(link.args) # optimization only return self.insert_renamings(link) - self.make_bytecode_block(link.target) + self.make_bytecode_block(link.target, handling_ovf) - def make_exception_link(self, link): + def make_exception_link(self, link, handling_ovf): # Like make_link(), but also introduces the 'last_exception' and # 'last_exc_value' as variables if needed. Also check if the link # is jumping directly to the re-raising exception block. @@ -159,19 +162,26 @@ assert link.last_exc_value is not None if link.target.operations == () and link.args == [link.last_exception, link.last_exc_value]: - self.emitline("reraise") + if handling_ovf: + exc_data = self.cpu.rtyper.exceptiondata + ll_ovf = exc_data.get_standard_ll_exc_instance_by_class( + OverflowError) + c = Constant(ll_ovf, concretetype=lltype.Void) + self.emitline("raise", c) + else: + self.emitline("reraise") self.emitline("---") return # done - self.make_link(link) + self.make_link(link, handling_ovf) - def insert_exits(self, block): + def insert_exits(self, block, handling_ovf=False): if len(block.exits) == 1: # A single link, fall-through link = block.exits[0] assert link.exitcase in (None, False, True) # the cases False or True should not really occur, but can show # up in the manually hacked graphs for generators... - self.make_link(link) + self.make_link(link, handling_ovf) # elif block.canraise: # An exception block. See test_exc_exitswitch in test_flatten.py @@ -185,9 +195,9 @@ self.emitline(opname[:7] + '_jump_if_ovf', TLabel(block.exits[1]), *line[1:]) assert len(block.exits) == 2 - self.make_link(block.exits[0]) + self.make_link(block.exits[0], False) self.emitline(Label(block.exits[1])) - self.make_exception_link(block.exits[1]) + self.make_exception_link(block.exits[1], True) return else: while True: @@ -201,22 +211,22 @@ if index == -1: # cannot raise: the last instruction is not # actually a '-live-' - self.make_link(block.exits[0]) + self.make_link(block.exits[0], False) return # self.emitline('catch_exception', TLabel(block.exits[0])) - self.make_link(block.exits[0]) + self.make_link(block.exits[0], False) self.emitline(Label(block.exits[0])) for link in block.exits[1:]: if link.exitcase is Exception: # this link captures all exceptions - self.make_exception_link(link) + self.make_exception_link(link, False) break self.emitline('goto_if_exception_mismatch', Constant(link.llexitcase, lltype.typeOf(link.llexitcase)), TLabel(link)) - self.make_exception_link(link) + self.make_exception_link(link, False) self.emitline(Label(link)) else: # no link captures all exceptions, so we have to put a reraise @@ -248,10 +258,10 @@ #if not livebefore: # self.emitline('-live-', TLabel(linkfalse)) # true path: - self.make_link(linktrue) + self.make_link(linktrue, handling_ovf) # false path: self.emitline(Label(linkfalse)) - self.make_link(linkfalse) + self.make_link(linkfalse, handling_ovf) # else: # A switch. @@ -274,7 +284,7 @@ switchdict) # emit the default path if block.exits[-1].exitcase == 'default': - self.make_link(block.exits[-1]) + self.make_link(block.exits[-1], handling_ovf) else: self.emitline("unreachable") self.emitline("---") @@ -288,7 +298,7 @@ # if the switched value doesn't match any case. self.emitline(Label(switch)) self.emitline('-live-') - self.make_link(switch) + self.make_link(switch, handling_ovf) def insert_renamings(self, link): renamings = {} diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py --- a/rpython/jit/codewriter/test/test_flatten.py +++ b/rpython/jit/codewriter/test/test_flatten.py @@ -140,6 +140,7 @@ def encoding_test(self, func, args, expected, transform=False, liveness=False, cc=None, jd=None): + graphs = self.make_graphs(func, args) #graphs[0].show() if transform: @@ -147,7 +148,8 @@ cc = cc or FakeCallControl() transform_graph(graphs[0], FakeCPU(self.rtyper), cc, jd) ssarepr = flatten_graph(graphs[0], fake_regallocs(), - _include_all_exc_links=not transform) + _include_all_exc_links=not transform, + cpu=FakeCPU(self.rtyper)) if liveness: from rpython.jit.codewriter.liveness import compute_liveness compute_liveness(ssarepr) @@ -576,6 +578,21 @@ "transform=True, liveness=True)") assert "ovfcheck()" in str(err) + def test_ovfcheck_reraise(self): + def f(i, j): + try: + ovfcheck(j + i) + except OverflowError: + raise + self.encoding_test(f, [7, 2], """ + -live- %i0, %i1 + int_add_jump_if_ovf L1, %i1, %i0 -> %i2 + void_return + --- + L1: + raise $<* struct object { typeptr=... }> + """, transform=True, liveness=True) + def test_residual_call_raising(self): @dont_look_inside def g(i, j): From noreply at buildbot.pypy.org Mon Sep 21 20:58:48 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 20:58:48 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: kill guard_opnum Message-ID: <20150921185848.9BE441C1379@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79745:8588d6767134 Date: 2015-09-21 20:59 +0200 http://bitbucket.org/pypy/pypy/changeset/8588d6767134/ Log: kill guard_opnum 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 @@ -1465,58 +1465,9 @@ assert kind == 'v' return lltype.nullptr(rclass.OBJECTPTR.TO) - def _prepare_resume_from_failure(self, opnum, deadframe): - from rpython.jit.metainterp.resoperation import rop - # - if opnum == rop.GUARD_FUTURE_CONDITION: - pass - elif opnum == rop.GUARD_TRUE: - # Produced directly by some goto_if_not_xxx() opcode that did not - # jump, but which must now jump. The pc is just after the opcode. - pass # self.position = self.jitcode.follow_jump(self.position) - # - elif opnum == rop.GUARD_FALSE: - # Produced directly by some goto_if_not_xxx() opcode that jumped, - # but which must no longer jump. The pc is just after the opcode. - pass - # - elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS: - # Produced by guard_class(), xxx_guard_value(), or a few other - # opcodes like switch(). The pc is at the start of the opcode - # (so it will be redone). - pass - # - elif (opnum == rop.GUARD_NONNULL or - opnum == rop.GUARD_ISNULL or - opnum == rop.GUARD_NONNULL_CLASS): - # Produced by goto_if_not_ptr_{non,is}zero(). The pc is at the - # start of the opcode (so it will be redone); this is needed - # because of GUARD_NONNULL_CLASS. - pass - # - elif (opnum == rop.GUARD_NO_EXCEPTION or - opnum == rop.GUARD_EXCEPTION or - opnum == rop.GUARD_NOT_FORCED): - return lltype.cast_opaque_ptr(rclass.OBJECTPTR, - self.cpu.grab_exc_value(deadframe)) - # - elif opnum == rop.GUARD_NO_OVERFLOW: - # Produced by int_xxx_ovf(). The pc is just after the opcode. - # We get here because it did not used to overflow, but now it does. - #return get_llexception(self.cpu, OverflowError()) - pass - # - elif opnum == rop.GUARD_OVERFLOW: - # Produced by int_xxx_ovf(). The pc is just after the opcode. - # We get here because it used to overflow, but now it no longer - # does. - pass - elif opnum == rop.GUARD_NOT_INVALIDATED: - pass - else: - from rpython.jit.metainterp.resoperation import opname - raise NotImplementedError(opname[opnum]) - return lltype.nullptr(rclass.OBJECTPTR.TO) + def _prepare_resume_from_failure(self, deadframe): + return lltype.cast_opaque_ptr(rclass.OBJECTPTR, + self.cpu.grab_exc_value(deadframe)) # connect the return of values from the called frame to the # 'xxx_call_yyy' instructions from the caller frame @@ -1642,8 +1593,7 @@ deadframe, all_virtuals) - current_exc = blackholeinterp._prepare_resume_from_failure( - resumedescr.guard_opnum, deadframe) + current_exc = blackholeinterp._prepare_resume_from_failure(deadframe) _run_forever(blackholeinterp, current_exc) resume_in_blackhole._dont_inline_ = True diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -847,44 +847,8 @@ assert 0, box.type self.status = ty | (r_uint(i) << self.ST_SHIFT) -class ResumeGuardNonnullDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_NONNULL - -class ResumeGuardIsnullDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_ISNULL - -class ResumeGuardClassDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_CLASS - -class ResumeGuardTrueDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_TRUE - -class ResumeGuardFalseDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_FALSE - -class ResumeGuardNonnullClassDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_NONNULL_CLASS - -class ResumeGuardExceptionDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_EXCEPTION - -class ResumeGuardNoExceptionDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_NO_EXCEPTION - -class ResumeGuardOverflowDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_OVERFLOW - -class ResumeGuardNoOverflowDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_NO_OVERFLOW - -class ResumeGuardValueDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_VALUE - -class ResumeGuardNotInvalidated(ResumeGuardDescr): - guard_opnum = rop.GUARD_NOT_INVALIDATED - class ResumeAtPositionDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_FUTURE_CONDITION + pass class AllVirtuals: llopaque = True @@ -905,8 +869,6 @@ class ResumeGuardForcedDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_NOT_FORCED - def _init(self, metainterp_sd, jitdriver_sd): # to please the annotator self.metainterp_sd = metainterp_sd @@ -969,37 +931,11 @@ if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2: resumedescr = ResumeGuardForcedDescr() resumedescr._init(optimizer.metainterp_sd, optimizer.jitdriver_sd) - elif opnum == rop.GUARD_NOT_INVALIDATED: - resumedescr = ResumeGuardNotInvalidated() - elif opnum == rop.GUARD_FUTURE_CONDITION: - resumedescr = ResumeAtPositionDescr() - elif opnum == rop.GUARD_VALUE: - resumedescr = ResumeGuardValueDescr() - elif opnum == rop.GUARD_NONNULL: - resumedescr = ResumeGuardNonnullDescr() - elif opnum == rop.GUARD_ISNULL: - resumedescr = ResumeGuardIsnullDescr() - elif opnum == rop.GUARD_NONNULL_CLASS: - resumedescr = ResumeGuardNonnullClassDescr() - elif opnum == rop.GUARD_CLASS: - resumedescr = ResumeGuardClassDescr() - elif opnum == rop.GUARD_TRUE: - resumedescr = ResumeGuardTrueDescr() - elif opnum == rop.GUARD_FALSE: - resumedescr = ResumeGuardFalseDescr() - elif opnum == rop.GUARD_EXCEPTION: - resumedescr = ResumeGuardExceptionDescr() - elif opnum == rop.GUARD_NO_EXCEPTION: - resumedescr = ResumeGuardNoExceptionDescr() - elif opnum == rop.GUARD_OVERFLOW: - resumedescr = ResumeGuardOverflowDescr() - elif opnum == rop.GUARD_NO_OVERFLOW: - resumedescr = ResumeGuardNoOverflowDescr() elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE): # note - this only happens in tests resumedescr = ResumeAtPositionDescr() else: - assert False + resumedescr = ResumeGuardDescr() return resumedescr class ResumeFromInterpDescr(ResumeDescr): 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 @@ -115,10 +115,13 @@ while y > 0: myjitdriver.can_enter_jit(x=x, y=y, res=res) myjitdriver.jit_merge_point(x=x, y=y, res=res) - res += ovfcheck(x * x) - x += 1 - res += ovfcheck(x * x) - y -= 1 + try: + res += ovfcheck(x * x) + x += 1 + res += ovfcheck(x * x) + y -= 1 + except OverflowError: + assert 0 return res res = self.meta_interp(f, [6, 7]) assert res == 1323 From noreply at buildbot.pypy.org Mon Sep 21 21:28:06 2015 From: noreply at buildbot.pypy.org (mattip) Date: Mon, 21 Sep 2015 21:28:06 +0200 (CEST) Subject: [pypy-commit] pypy default: add product_check() to test overflow, be more careful about where this is needed Message-ID: <20150921192806.1E8211C01DE@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79746:8e3a27cadc69 Date: 2015-09-21 22:27 +0300 http://bitbucket.org/pypy/pypy/changeset/8e3a27cadc69/ Log: add product_check() to test overflow, be more careful about where this is needed diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,6 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype +from rpython.rlib.rarithmetic import ovfcheck from pypy.module.micronumpy import support from pypy.module.micronumpy import constants as NPY @@ -44,9 +45,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(shape) * dtype.elsize + ovfcheck(support.product_check(shape) * dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(shape, dtype.base, order) impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides, zero=zero) @@ -68,9 +69,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - totalsize = support.product(shape) * isize + totalsize = ovfcheck(support.product_check(shape) * isize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if storage_bytes > 0 : if totalsize > storage_bytes: raise OperationError(space.w_TypeError, space.wrap( diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc +from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -409,6 +410,7 @@ make_sure_not_resized(strides) make_sure_not_resized(backstrides) self.shape = shape + # already tested for overflow in from_shape_and_storage self.size = support.product(shape) * dtype.elsize self.order = order self.dtype = dtype @@ -428,9 +430,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(new_shape, self.dtype, self.order) return SliceArray(self.start, strides, backstrides, new_shape, self, @@ -457,8 +459,11 @@ storage=lltype.nullptr(RAW_STORAGE), zero=True): gcstruct = V_OBJECTSTORE flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE - length = support.product(shape) - self.size = length * dtype.elsize + try: + length = support.product_check(shape) + self.size = ovfcheck(length * dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") if storage == lltype.nullptr(RAW_STORAGE): if dtype.num == NPY.OBJECT: storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True) @@ -542,7 +547,10 @@ self.gcstruct = parent.gcstruct self.order = parent.order self.dtype = dtype - self.size = support.product(shape) * self.dtype.elsize + try: + self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED @@ -564,9 +572,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if len(self.get_shape()) < 2 or self.size == 0: # TODO: this code could be refactored into calc_strides # but then calc_strides would have to accept a stepping factor diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -153,7 +153,7 @@ dtype = descriptor.variable_dtype(space, dtype.char + '1') w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) - if support.product(shape) == 1: + if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: loop.assign(space, w_arr, elems_w) @@ -213,10 +213,9 @@ raise OperationError(space.w_ValueError, space.wrap( "negative dimensions are not allowed")) try: - support.product(shape) + support.product_check(shape) except OverflowError: - raise OperationError(space.w_ValueError, space.wrap( - "array is too big.")) + raise oefmt(space.w_ValueError, "array is too big.") return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -6,6 +6,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from rpython.rlib.rawstorage import RAW_STORAGE_PTR +from rpython.rlib.rarithmetic import ovfcheck from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy import descriptor, ufuncs, boxes, arrayops, loop, \ @@ -611,6 +612,7 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + # sz cannot overflow since self is valid sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, @@ -1405,9 +1407,9 @@ return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) try: - totalsize = support.product(shape) * dtype.base.elsize + totalsize = ovfcheck(support.product_check(shape) * dtype.base.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") impl = ConcreteArray(shape, dtype.base, order, strides, backstrides) w_ret = space.allocate_instance(W_NDimArray, w_subtype) W_NDimArray.__init__(w_ret, impl) diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -32,10 +32,16 @@ def product(s): i = 1 for x in s: + i *= x + return i + + at jit.unroll_safe +def product_check(s): + i = 1 + for x in s: i = ovfcheck(i * x) return i - def check_and_adjust_index(space, index, size, axis): if index < -size or index >= size: if axis >= 0: diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -270,7 +270,7 @@ exc = raises(ValueError, ndarray, [1,2,256]*10000) assert exc.value[0] == 'sequence too large; must be smaller than 32' exc = raises(ValueError, ndarray, [1,2,256]*10) - assert exc.value[0] == 'array is too big' + assert exc.value[0] == 'array is too big.' def test_ndmin(self): from numpy import array diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -1006,7 +1006,6 @@ assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): # reshape - sz = product(curarg.get_shape()) * curarg.get_dtype().elsize with curarg.implementation as storage: inargs[i] = W_NDimArray.from_shape_and_storage( From noreply at buildbot.pypy.org Mon Sep 21 21:55:38 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 21:55:38 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: progress on overflow Message-ID: <20150921195538.9ED041C1370@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79747:28f21fa3e33a Date: 2015-09-21 21:55 +0200 http://bitbucket.org/pypy/pypy/changeset/28f21fa3e33a/ Log: progress on overflow 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 @@ -402,9 +402,12 @@ def bhimpl_int_sub_ovf(a, b): return ovfcheck(a - b) - @arguments("i", "i", returns="i") - def bhimpl_int_mul_ovf(a, b): - return ovfcheck(a * b) + @arguments("L", "i", "i", returns="i") + def bhimpl_int_mul_jump_if_ovf(label, a, b): + try: + return ovfcheck(a * b) + except OverflowError: + xxx @arguments("i", "i", returns="i") def bhimpl_int_floordiv(a, b): diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -251,9 +251,10 @@ b = box2.getint() try: z = ovfcheck(a + b) + metainterp.ovf_flag = False except OverflowError: assert metainterp is not None - metainterp.execute_raised(OverflowError(), constant=True) + metainterp.ovf_flag = True z = 0 return z @@ -262,9 +263,10 @@ b = box2.getint() try: z = ovfcheck(a - b) + metainterp.ovf_flag = False except OverflowError: assert metainterp is not None - metainterp.execute_raised(OverflowError(), constant=True) + metainterp.ovf_flag = True z = 0 return z @@ -273,9 +275,10 @@ b = box2.getint() try: z = ovfcheck(a * b) + metainterp.ovf_flag = False except OverflowError: assert metainterp is not None - metainterp.execute_raised(OverflowError(), constant=True) + metainterp.ovf_flag = True z = 0 return z 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 @@ -228,17 +228,19 @@ ''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper()) ).compile() - for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']: + for (_opimpl, resop) in [ + ('int_add_jump_if_ovf', 'INT_ADD_OVF'), + ('int_sub_jump_if_ovf', 'INT_SUB_OVF'), + ('int_mul_jump_if_ovf', 'INT_MUL_OVF')]: exec py.code.Source(''' - @arguments("box", "box", "orgpc") - def opimpl_%s(self, b1, b2, orgpc): - self.metainterp.clear_exception() + @arguments("label", "box", "box", "orgpc") + def opimpl_%s(self, lbl, b1, b2, orgpc): resbox = self.execute(rop.%s, b1, b2) self.make_result_of_lastop(resbox) # same as execute_varargs() if not isinstance(resbox, Const): - self.metainterp.handle_possible_overflow_error(orgpc) + self.metainterp.handle_possible_overflow_error(lbl, orgpc) return resbox - ''' % (_opimpl, _opimpl.upper())).compile() + ''' % (_opimpl, resop)).compile() for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert', 'cast_float_to_int', 'cast_int_to_float', @@ -2308,7 +2310,7 @@ if isinstance(key, compile.ResumeAtPositionDescr): self.seen_loop_header_for_jdindex = self.jitdriver_sd.index try: - self.prepare_resume_from_failure(key.guard_opnum, deadframe) + self.prepare_resume_from_failure(deadframe) if self.resumekey_original_loop_token is None: # very rare case raise SwitchToBlackhole(Counters.ABORT_BRIDGE) self.interpret() @@ -2451,7 +2453,8 @@ else: assert 0 self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args) - def prepare_resume_from_failure(self, opnum, deadframe): + def prepare_resume_from_failure(self, deadframe): + xxx frame = self.framestack[-1] if opnum == rop.GUARD_FUTURE_CONDITION: pass @@ -2773,15 +2776,10 @@ else: self.generate_guard(rop.GUARD_NO_EXCEPTION, None, []) - def handle_possible_overflow_error(self, orgpc): - if self.last_exc_value: - op = self.generate_guard(rop.GUARD_OVERFLOW, None, resumepc=orgpc) - op.setref_base(lltype.cast_opaque_ptr(llmemory.GCREF, - self.last_exc_value)) - assert self.class_of_last_exc_is_const - self.last_exc_box = ConstPtr( - lltype.cast_opaque_ptr(llmemory.GCREF, self.last_exc_value)) - self.finishframe_exception() + def handle_possible_overflow_error(self, label, orgpc): + if self.ovf_flag: + self.generate_guard(rop.GUARD_OVERFLOW, None, resumepc=orgpc) + self.pc = label else: self.generate_guard(rop.GUARD_NO_OVERFLOW, None, resumepc=orgpc) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -691,7 +691,7 @@ 'GUARD_NO_EXCEPTION/0d/n', # may be called with an exception currently set 'GUARD_EXCEPTION/1d/r', # may be called with an exception currently set 'GUARD_NO_OVERFLOW/0d/n', - 'GUARD_OVERFLOW/0d/r', + 'GUARD_OVERFLOW/0d/n', 'GUARD_NOT_FORCED/0d/n', # may be called with an exception currently set 'GUARD_NOT_FORCED_2/0d/n', # same as GUARD_NOT_FORCED, but for finish() 'GUARD_NOT_INVALIDATED/0d/n', 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 @@ -154,7 +154,10 @@ myjitdriver.can_enter_jit(x=x, y=y, res=res) myjitdriver.jit_merge_point(x=x, y=y, res=res) b = y * 2 - res += ovfcheck(x * x) + b + try: + res += ovfcheck(x * x) + b + except OverflowError: + assert 0 y -= 1 return res res = self.meta_interp(f, [6, 7]) From noreply at buildbot.pypy.org Mon Sep 21 22:25:26 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 21 Sep 2015 22:25:26 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: I don't know how to handle exceptions yet Message-ID: <20150921202526.D7A111C0325@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79748:defd45638c14 Date: 2015-09-21 22:25 +0200 http://bitbucket.org/pypy/pypy/changeset/defd45638c14/ Log: I don't know how to handle exceptions yet 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 @@ -1028,7 +1028,6 @@ def execute_guard_overflow(self, descr): if not self.overflow_flag: self.fail_guard(descr) - return lltype.nullptr(llmemory.GCREF.TO) # I think it's fine.... def execute_jump(self, descr, *args): raise Jump(descr._llgraph_target, args) 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 @@ -212,6 +212,20 @@ assert lltype.typeOf(result) is longlong.FLOATSTORAGE self.registers_f[ord(code[position])] = result position += 1 + elif resulttype == "iL": + result, new_position = result + if new_position != -1: + position = new_position + next_argcode = next_argcode + 2 + else: + assert argcodes[next_argcode] == '>' + assert argcodes[next_argcode + 1] == 'i' + next_argcode = next_argcode + 2 + if lltype.typeOf(result) is lltype.Bool: + result = int(result) + assert lltype.typeOf(result) is lltype.Signed + self.registers_i[ord(code[position])] = result + position += 1 elif resulttype == 'L': assert result >= 0 position = result @@ -402,12 +416,12 @@ def bhimpl_int_sub_ovf(a, b): return ovfcheck(a - b) - @arguments("L", "i", "i", returns="i") + @arguments("L", "i", "i", returns="iL") def bhimpl_int_mul_jump_if_ovf(label, a, b): try: - return ovfcheck(a * b) + return ovfcheck(a * b), -1 except OverflowError: - xxx + return 0, label @arguments("i", "i", returns="i") def bhimpl_int_floordiv(a, b): 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 @@ -2023,7 +2023,7 @@ moreargs = [box] + extraargs else: moreargs = list(extraargs) - if opnum == rop.GUARD_EXCEPTION or opnum == rop.GUARD_OVERFLOW: + if opnum == rop.GUARD_EXCEPTION: guard_op = self.history.record(opnum, moreargs, lltype.nullptr(llmemory.GCREF.TO)) else: @@ -2454,46 +2454,16 @@ self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args) def prepare_resume_from_failure(self, deadframe): - xxx - frame = self.framestack[-1] - if opnum == rop.GUARD_FUTURE_CONDITION: - pass - elif opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now - pass # frame.pc = frame.jitcode.follow_jump(frame.pc) - elif opnum == rop.GUARD_FALSE: # a goto_if_not that stops jumping; - pass # or a switch that was in its "default" case - elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS: - pass # the pc is already set to the *start* of the opcode - elif (opnum == rop.GUARD_NONNULL or - opnum == rop.GUARD_ISNULL or - opnum == rop.GUARD_NONNULL_CLASS): - pass # the pc is already set to the *start* of the opcode - elif opnum == rop.GUARD_NO_EXCEPTION or opnum == rop.GUARD_EXCEPTION: - exception = self.cpu.grab_exc_value(deadframe) - if exception: - self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, - exception)) - else: - self.clear_exception() - try: - self.handle_possible_exception() - except ChangeFrame: - pass - elif opnum == rop.GUARD_NOT_INVALIDATED: - pass # XXX we want to do something special in resume descr, - # but not now - elif opnum == rop.GUARD_NO_OVERFLOW: # an overflow now detected - pass - #self.execute_raised(OverflowError(), constant=True) - #try: - # self.finishframe_exception() - #except ChangeFrame: - # pass - elif opnum == rop.GUARD_OVERFLOW: # no longer overflowing - self.clear_exception() - else: - from rpython.jit.metainterp.resoperation import opname - raise NotImplementedError(opname[opnum]) + exception = self.cpu.grab_exc_value(deadframe) + if exception: + self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, + exception)) + #else: + # self.clear_exception() + #try: + # self.handle_possible_exception() + #except ChangeFrame: + # pass def get_procedure_token(self, greenkey, with_compiled_targets=False): JitCell = self.jitdriver_sd.warmstate.JitCell From noreply at buildbot.pypy.org Tue Sep 22 08:42:47 2015 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 22 Sep 2015 08:42:47 +0200 (CEST) Subject: [pypy-commit] pypy default: update link fixes issue #2140 Message-ID: <20150922064247.839D61C0325@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79749:e68fc7564327 Date: 2015-09-22 09:43 +0300 http://bitbucket.org/pypy/pypy/changeset/e68fc7564327/ Log: update link fixes issue #2140 diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -67,7 +67,7 @@ The other commands of ``setup.py`` are available too, like ``build``. .. _PyPI: https://pypi.python.org/pypi -.. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv +.. _`use virtualenv (as documented here)`: install.html#installing-using-virtualenv Module xyz does not work in the sandboxed PyPy? From noreply at buildbot.pypy.org Tue Sep 22 10:57:00 2015 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 22 Sep 2015 10:57:00 +0200 (CEST) Subject: [pypy-commit] pypy value-profiling: merge default Message-ID: <20150922085700.9AB0A1C0325@cobra.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: value-profiling Changeset: r79750:95fb006bbdff Date: 2015-09-22 10:57 +0200 http://bitbucket.org/pypy/pypy/changeset/95fb006bbdff/ Log: merge default diff too long, truncating to 2000 out of 3446 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -92,6 +92,8 @@ if sys.platform == "win32": module_suggests["cpyext"].append(("translation.shared", True)) + +# NOTE: this dictionary is not used any more module_import_dependencies = { # no _rawffi if importing rpython.rlib.clibffi raises ImportError # or CompilationError or py.test.skip.Exception @@ -108,6 +110,7 @@ } def get_module_validator(modname): + # NOTE: this function is not used any more if modname in module_import_dependencies: modlist = module_import_dependencies[modname] def validator(config): diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -67,7 +67,7 @@ The other commands of ``setup.py`` are available too, like ``build``. .. _PyPI: https://pypi.python.org/pypi -.. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv +.. _`use virtualenv (as documented here)`: install.html#installing-using-virtualenv Module xyz does not work in the sandboxed PyPy? diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -5,19 +5,8 @@ understanding what's pypy's JIT doing while running your program. There are three functions related to that coming from the ``pypyjit`` module: -.. function:: set_optimize_hook(callable) - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The callable will be called with the ``pypyjit.JitLoopInfo`` object. - Refer to it's documentation for details. - - Result value will be the resulting list of operations, or None - - -.. function:: set_compile_hook(callable) +.. function:: set_compile_hook(callable, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -28,6 +17,9 @@ inside the jit hook is itself jitted, it will get compiled, but the jit hook won't be called for that. + if operations=False, no list of operations will be available. Useful + if the hook is supposed to be very lighweight. + .. function:: set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing @@ -66,3 +58,25 @@ * ``loop_run_times`` - counters for number of times loops are run, only works when ``enable_debug`` is called. + +.. class:: JitLoopInfo + + A class containing information about the compiled loop. Usable attributes: + + * ``operations`` - list of operations, if requested + + * ``jitdriver_name`` - the name of jitdriver associated with this loop + + * ``greenkey`` - a key at which the loop got compiled (e.g. code position, + is_being_profiled, pycode tuple for python jitdriver) + + * ``loop_no`` - loop cardinal number + + * ``bridge_no`` - id of the fail descr + + * ``type`` - "entry bridge", "loop" or "bridge" + + * ``asmaddr`` - an address in raw memory where assembler resides + + * ``asmlen`` - length of raw memory with assembler associated + 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 @@ -21,3 +21,15 @@ .. branch: missing_openssl_include Fix for missing headers in OpenBSD, already applied in downstream ports + +.. branch: gc-more-incremental +Remove a source of non-incremental-ness in the GC: now +external_malloc() no longer runs gc_step_until() any more. If there +is a currently-running major collection, we do only so many steps +before returning. This number of steps depends on the size of the +allocated object. It is controlled by tracking the general progress +of these major collection steps and the size of old objects that +keep adding up between them. + +.. branch: remember-tracing-counts +Reenable jithooks diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - #from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy()#pypy_hooks) + from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,6 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype +from rpython.rlib.rarithmetic import ovfcheck from pypy.module.micronumpy import support from pypy.module.micronumpy import constants as NPY @@ -44,9 +45,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(shape) * dtype.elsize + ovfcheck(support.product_check(shape) * dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(shape, dtype.base, order) impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides, zero=zero) @@ -68,9 +69,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - totalsize = support.product(shape) * isize + totalsize = ovfcheck(support.product_check(shape) * isize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if storage_bytes > 0 : if totalsize > storage_bytes: raise OperationError(space.w_TypeError, space.wrap( diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc +from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -409,6 +410,7 @@ make_sure_not_resized(strides) make_sure_not_resized(backstrides) self.shape = shape + # already tested for overflow in from_shape_and_storage self.size = support.product(shape) * dtype.elsize self.order = order self.dtype = dtype @@ -428,9 +430,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(new_shape, self.dtype, self.order) return SliceArray(self.start, strides, backstrides, new_shape, self, @@ -457,8 +459,11 @@ storage=lltype.nullptr(RAW_STORAGE), zero=True): gcstruct = V_OBJECTSTORE flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE - length = support.product(shape) - self.size = length * dtype.elsize + try: + length = support.product_check(shape) + self.size = ovfcheck(length * dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") if storage == lltype.nullptr(RAW_STORAGE): if dtype.num == NPY.OBJECT: storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True) @@ -542,7 +547,10 @@ self.gcstruct = parent.gcstruct self.order = parent.order self.dtype = dtype - self.size = support.product(shape) * self.dtype.elsize + try: + self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED @@ -564,9 +572,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if len(self.get_shape()) < 2 or self.size == 0: # TODO: this code could be refactored into calc_strides # but then calc_strides would have to accept a stepping factor diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -153,7 +153,7 @@ dtype = descriptor.variable_dtype(space, dtype.char + '1') w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) - if support.product(shape) == 1: + if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: loop.assign(space, w_arr, elems_w) @@ -213,10 +213,9 @@ raise OperationError(space.w_ValueError, space.wrap( "negative dimensions are not allowed")) try: - support.product(shape) + support.product_check(shape) except OverflowError: - raise OperationError(space.w_ValueError, space.wrap( - "array is too big.")) + raise oefmt(space.w_ValueError, "array is too big.") return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -6,6 +6,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from rpython.rlib.rawstorage import RAW_STORAGE_PTR +from rpython.rlib.rarithmetic import ovfcheck from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy import descriptor, ufuncs, boxes, arrayops, loop, \ @@ -611,6 +612,7 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + # sz cannot overflow since self is valid sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, @@ -1405,9 +1407,9 @@ return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) try: - totalsize = support.product(shape) * dtype.base.elsize + totalsize = ovfcheck(support.product_check(shape) * dtype.base.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") impl = ConcreteArray(shape, dtype.base, order, strides, backstrides) w_ret = space.allocate_instance(W_NDimArray, w_subtype) W_NDimArray.__init__(w_ret, impl) diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -32,10 +32,16 @@ def product(s): i = 1 for x in s: + i *= x + return i + + at jit.unroll_safe +def product_check(s): + i = 1 + for x in s: i = ovfcheck(i * x) return i - def check_and_adjust_index(space, index, size, axis): if index < -size or index >= size: if axis >= 0: diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -270,7 +270,7 @@ exc = raises(ValueError, ndarray, [1,2,256]*10000) assert exc.value[0] == 'sequence too large; must be smaller than 32' exc = raises(ValueError, ndarray, [1,2,256]*10) - assert exc.value[0] == 'array is too big' + assert exc.value[0] == 'array is too big.' def test_ndmin(self): from numpy import array diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -1006,7 +1006,6 @@ assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): # reshape - sz = product(curarg.get_shape()) * curarg.get_dtype().elsize with curarg.implementation as storage: inargs[i] = W_NDimArray.from_shape_and_storage( diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,18 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - #'set_compile_hook': 'interp_resop.set_compile_hook', - #'set_optimize_hook': 'interp_resop.set_optimize_hook', - #'set_abort_hook': 'interp_resop.set_abort_hook', - #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - #'enable_debug': 'interp_resop.enable_debug', - #'disable_debug': 'interp_resop.disable_debug', - #'ResOperation': 'interp_resop.WrappedOp', - #'DebugMergePoint': 'interp_resop.DebugMergePoint', - #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - #'Box': 'interp_resop.WrappedBox', + 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', + 'dont_trace_here': 'interp_jit.dont_trace_here', + 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', + 'set_compile_hook': 'interp_resop.set_compile_hook', + 'set_abort_hook': 'interp_resop.set_abort_hook', + 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + 'enable_debug': 'interp_resop.enable_debug', + 'disable_debug': 'interp_resop.disable_debug', + 'ResOperation': 'interp_resop.WrappedOp', + 'DebugMergePoint': 'interp_resop.DebugMergePoint', + 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -35,10 +35,10 @@ self._compile_hook(debug_info, is_bridge=True) def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) + pass def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) + pass def _compile_hook(self, debug_info, is_bridge): space = self.space @@ -46,7 +46,8 @@ if cache.in_recursion: return if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.compile_hook_with_ops) cache.in_recursion = True try: try: @@ -57,33 +58,4 @@ finally: cache.in_recursion = False - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -5,11 +5,14 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside -from rpython.rlib import jit -from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rlib import jit, jit_hooks +from rpython.rlib.jit import current_trace_length, unroll_parameters,\ + JitHookInterface +from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.pycode import CO_GENERATOR, PyCode +from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame, Yield from pypy.interpreter.baseobjspace import W_Root @@ -188,3 +191,100 @@ __call__ = interp2app(W_NotFromAssembler.descr_call), ) W_NotFromAssembler.typedef.acceptable_as_base_class = False + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + return space.wrap(bool(jit_hooks.get_jitcell_at_key( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode))) + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.dont_trace_here( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.trace_next_iteration( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(hash=r_uint) + at dont_look_inside +def trace_next_iteration_hash(space, hash): + jit_hooks.trace_next_iteration_hash('pypyjit', hash) + return space.w_None + +# class Cache(object): +# in_recursion = False + +# def __init__(self, space): +# self.w_compile_bridge = space.w_None +# self.w_compile_loop = space.w_None + +# def set_compile_bridge(space, w_hook): +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_bridge = w_hook + +# def set_compile_loop(space, w_hook): +# from rpython.rlib.nonconst import NonConstant + +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_loop = w_hook +# cache.in_recursion = NonConstant(False) + +# class PyPyJitHookInterface(JitHookInterface): +# def after_compile(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# l_w = [] +# if not space.is_true(cache.w_compile_loop): +# return +# for i, op in enumerate(debug_info.operations): +# if op.is_guard(): +# w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) +# l_w.append(w_t) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_loop, space.newlist(l_w)) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def after_compile_bridge(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# if not space.is_true(cache.w_compile_bridge): +# return +# w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_bridge, w_hash) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def before_compile(self, debug_info): +# pass + +# def before_compile_bridge(self, debug_info): +# pass + +# pypy_hooks = PyPyJitHookInterface() + diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -22,7 +22,6 @@ def __init__(self, space): self.w_compile_hook = space.w_None self.w_abort_hook = space.w_None - self.w_optimize_hook = space.w_None def getno(self): self.no += 1 @@ -43,8 +42,9 @@ else: return space.wrap(greenkey_repr) -def set_compile_hook(space, w_hook): - """ set_compile_hook(hook) + at unwrap_spec(operations=bool) +def set_compile_hook(space, w_hook, operations=True): + """ set_compile_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -58,25 +58,9 @@ cache = space.fromcache(Cache) assert w_hook is not None cache.w_compile_hook = w_hook + cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) -def set_optimize_hook(space, w_hook): - """ set_optimize_hook(hook) - - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's - docstring for details. - - Result value will be the resulting list of operations, or None - """ - cache = space.fromcache(Cache) - cache.w_optimize_hook = w_hook - cache.in_recursion = NonConstant(False) - - def set_abort_hook(space, w_hook): """ set_abort_hook(hook) @@ -96,6 +80,9 @@ cache.in_recursion = NonConstant(False) def wrap_oplist(space, logops, operations, ops_offset=None): + # this function is called from the JIT + from rpython.jit.metainterp.resoperation import rop + l_w = [] jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd for op in operations: @@ -103,117 +90,58 @@ ofs = -1 else: ofs = ops_offset.get(op, 0) - if op.opnum == rop.DEBUG_MERGE_POINT: + num = op.getopnum() + name = op.getopname() + if num == rop.DEBUG_MERGE_POINT: jd_sd = jitdrivers_sd[op.getarg(0).getint()] greenkey = op.getarglist()[3:] repr = jd_sd.warmstate.get_location_str(greenkey) w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr) - l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op), + l_w.append(DebugMergePoint(space, name, logops.repr_of_resop(op), jd_sd.jitdriver.name, op.getarg(1).getint(), op.getarg(2).getint(), w_greenkey)) else: - l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs, - logops.repr_of_resop(op))) + l_w.append(WrappedOp(name, ofs, logops.repr_of_resop(op))) return l_w + at unwrap_spec(offset=int, repr=str, name=str) +def descr_new_resop(space, w_tp, name, offset=-1, repr=''): + return WrappedOp(name, offset, repr) -class WrappedBox(W_Root): - """ A class representing a single box - """ - def __init__(self, llbox): - self.llbox = llbox - - def descr_getint(self, space): - if not jit_hooks.box_isint(self.llbox): - raise OperationError(space.w_NotImplementedError, - space.wrap("Box has no int value")) - return space.wrap(jit_hooks.box_getint(self.llbox)) - - at unwrap_spec(no=int) -def descr_new_box(space, w_tp, no): - return WrappedBox(jit_hooks.boxint_new(no)) - -WrappedBox.typedef = TypeDef( - 'Box', - __new__ = interp2app(descr_new_box), - getint = interp2app(WrappedBox.descr_getint), -) - - at unwrap_spec(num=int, offset=int, repr=str, w_res=W_Root) -def descr_new_resop(space, w_tp, num, w_args, w_res, offset=-1, - repr=''): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - if space.is_none(w_res): - llres = jit_hooks.emptyval() - else: - if not isinstance(w_res, WrappedBox): - raise OperationError(space.w_TypeError, space.wrap( - "expected box type, got %s" % space.type(w_res))) - llres = w_res.llbox - return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr) - - at unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int) -def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id, + at unwrap_spec(repr=str, name=str, jd_name=str, call_depth=int, call_id=int) +def descr_new_dmp(space, w_tp, name, repr, jd_name, call_depth, call_id, w_greenkey): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - num = rop.DEBUG_MERGE_POINT - return DebugMergePoint(space, - jit_hooks.resop_new(num, args, jit_hooks.emptyval()), + return DebugMergePoint(space, name, repr, jd_name, call_depth, call_id, w_greenkey) class WrappedOp(W_Root): """ A class representing a single ResOperation, wrapped nicely """ - def __init__(self, op, offset, repr_of_resop): - self.op = op + def __init__(self, name, offset, repr_of_resop): self.offset = offset + self.name = name self.repr_of_resop = repr_of_resop def descr_repr(self, space): return space.wrap(self.repr_of_resop) - def descr_num(self, space): - return space.wrap(jit_hooks.resop_getopnum(self.op)) - def descr_name(self, space): - return space.wrap(hlstr(jit_hooks.resop_getopname(self.op))) - - @unwrap_spec(no=int) - def descr_getarg(self, space, no): - try: - box = jit_hooks.resop_getarg(self.op, no) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("Index out of range")) - return WrappedBox(box) - - @unwrap_spec(no=int, w_box=WrappedBox) - def descr_setarg(self, space, no, w_box): - jit_hooks.resop_setarg(self.op, no, w_box.llbox) - - def descr_getresult(self, space): - return WrappedBox(jit_hooks.resop_getresult(self.op)) - - def descr_setresult(self, space, w_box): - box = space.interp_w(WrappedBox, w_box) - jit_hooks.resop_setresult(self.op, box.llbox) + return space.wrap(self.name) class DebugMergePoint(WrappedOp): """ A class representing Debug Merge Point - the entry point to a jitted loop. """ - def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id, - w_greenkey): + def __init__(self, space, name, repr_of_resop, jd_name, call_depth, + call_id, w_greenkey): - WrappedOp.__init__(self, op, -1, repr_of_resop) + WrappedOp.__init__(self, name, -1, repr_of_resop) self.jd_name = jd_name self.call_depth = call_depth self.call_id = call_id @@ -237,12 +165,7 @@ __doc__ = WrappedOp.__doc__, __new__ = interp2app(descr_new_resop), __repr__ = interp2app(WrappedOp.descr_repr), - num = GetSetProperty(WrappedOp.descr_num), name = GetSetProperty(WrappedOp.descr_name), - getarg = interp2app(WrappedOp.descr_getarg), - setarg = interp2app(WrappedOp.descr_setarg), - result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult), offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.typedef.acceptable_as_base_class = False @@ -278,14 +201,18 @@ asmaddr = 0 asmlen = 0 - def __init__(self, space, debug_info, is_bridge=False): - logops = debug_info.logger._make_log_operations() - if debug_info.asminfo is not None: - ofs = debug_info.asminfo.ops_offset + def __init__(self, space, debug_info, is_bridge=False, wrap_ops=True): + if wrap_ops: + memo = {} + logops = debug_info.logger._make_log_operations(memo) + if debug_info.asminfo is not None: + ofs = debug_info.asminfo.ops_offset + else: + ofs = {} + ops = debug_info.operations + self.w_ops = space.newlist(wrap_oplist(space, logops, ops, ofs)) else: - ofs = {} - self.w_ops = space.newlist( - wrap_oplist(space, logops, debug_info.operations, ofs)) + self.w_ops = space.w_None self.jd_name = debug_info.get_jitdriver().name self.type = debug_info.type diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -136,7 +136,6 @@ assert dmp.call_id == 0 assert dmp.offset == -1 assert int_add.name == 'int_add' - assert int_add.num == self.int_add_num assert int_add.offset == 0 self.on_compile_bridge() expected = (') i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) setfield_gc(p167, i119, descr=) - i123 = arraylen_gc(p67, descr=) jump(..., descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -47,7 +47,7 @@ i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) - p34 = new_with_vtable(#) + p34 = new_with_vtable(descr=...) {{{ setfield_gc(p34, p1, descr=) setfield_gc(p34, i25, descr=) @@ -154,7 +154,7 @@ f86 = float_add(f74, f85) i87 = int_add(i76, 1) --TICK-- - jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...) + jump(..., descr=...) """) def test_array_flatiter_next(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -148,6 +148,7 @@ i18 = force_token() setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>) guard_not_invalidated(descr=...) + i84 = int_sub(i14, 1) i21 = int_lt(i10, 0) guard_false(i21, descr=...) i22 = int_lt(i10, i14) @@ -180,6 +181,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i88 = int_sub(i9, 1) i25 = int_ge(i11, i9) guard_false(i25, descr=...) i27 = int_add_ovf(i7, i11) @@ -212,6 +214,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i95 = int_sub(i9, 1) i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -385,7 +385,8 @@ class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeCodePoint)): def union((uchr1, uchr2)): - return SomeUnicodeCodePoint() + no_nul = uchr1.no_nul and uchr2.no_nul + return SomeUnicodeCodePoint(no_nul=no_nul) def add((chr1, chr2)): return SomeUnicodeString() @@ -598,32 +599,33 @@ class __extend__(pairtype(SomeUnicodeString, SomeInteger)): def getitem((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem.can_only_throw = [] def getitem_idx((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem_idx.can_only_throw = [IndexError] def mul((str1, int2)): # xxx do we want to support this - return SomeUnicodeString() + return SomeUnicodeString(no_nul=str1.no_nul) class __extend__(pairtype(SomeInteger, SomeString), pairtype(SomeInteger, SomeUnicodeString)): def mul((int1, str2)): # xxx do we want to support this - return str2.basestringclass() + return str2.basestringclass(no_nul=str2.no_nul) class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeString), pairtype(SomeUnicodeString, SomeUnicodeCodePoint), pairtype(SomeUnicodeString, SomeUnicodeString)): def union((str1, str2)): - return SomeUnicodeString(can_be_None=str1.can_be_none() or - str2.can_be_none()) + can_be_None = str1.can_be_None or str2.can_be_None + no_nul = str1.no_nul and str2.no_nul + return SomeUnicodeString(can_be_None=can_be_None, no_nul=no_nul) def add((str1, str2)): # propagate const-ness to help getattr(obj, 'prefix' + const_name) - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=str1.no_nul and str2.no_nul) if str1.is_immutable_constant() and str2.is_immutable_constant(): result.const = str1.const + str2.const return result diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -237,10 +237,11 @@ else: result = SomeString(no_nul=no_nul) elif tp is unicode: + no_nul = not u'\x00' in x if len(x) == 1: - result = SomeUnicodeCodePoint() + result = SomeUnicodeCodePoint(no_nul=no_nul) else: - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=no_nul) elif tp is bytearray: result = SomeByteArray() elif tp is tuple: diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -438,6 +438,18 @@ assert s.knowntype == str assert s.no_nul + def test_unicode_join(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return [u"foo", u"bar"] + def f(n): + g(0) + return u''.join(g(n)) + s = a.build_types(f, [int]) + assert s.knowntype == unicode + assert s.no_nul + def test_str_split(self): a = self.RPythonAnnotator() def g(n): @@ -451,6 +463,19 @@ s_item = s.listdef.listitem.s_value assert s_item.no_nul + def test_unicode_split(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return u"test string" + def f(n): + if n: + return g(n).split(u' ') + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeList) + s_item = s.listdef.listitem.s_value + assert s_item.no_nul + def test_str_split_nul(self): def f(n): return n.split('\0')[0] @@ -470,6 +495,27 @@ assert not s.can_be_None assert not s.no_nul + def test_unicode_split_nul(self): + def f(n): + return n.split(u'\0')[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert s.no_nul + + def g(n): + return n.split(u'\0', 1)[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(g, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert not s.no_nul + def test_str_splitlines(self): a = self.RPythonAnnotator() def f(a_str): @@ -490,6 +536,18 @@ s = a.build_types(f, [int, annmodel.SomeString(no_nul=True)]) assert s.no_nul + def test_unicode_strip(self): + a = self.RPythonAnnotator() + def f(n, a_str): + if n == 0: + return a_str.strip(u' ') + elif n == 1: + return a_str.rstrip(u' ') + else: + return a_str.lstrip(u' ') + s = a.build_types(f, [int, annmodel.SomeUnicodeString(no_nul=True)]) + assert s.no_nul + def test_str_mul(self): a = self.RPythonAnnotator() def f(a_str): @@ -2042,6 +2100,17 @@ assert s.can_be_None assert s.no_nul + def test_unicode_noNUL_canbeNone(self): + def f(a): + if a: + return u"abc" + else: + return None + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_str_or_None(self): def f(a): if a: @@ -2058,6 +2127,22 @@ assert s.can_be_None assert s.no_nul + def test_unicode_or_None(self): + def f(a): + if a: + return u"abc" + else: + return None + def g(a): + x = f(a) + if x is None: + return u"abcd" + return x + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_emulated_pbc_call_simple(self): def f(a,b): return a + b @@ -2124,6 +2209,19 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_iteritems_unicode0(self): + def it(d): + return d.iteritems() + def f(): + d0 = {u'1a': u'2a', u'3': u'4'} + for item in it(d0): + return u"%s=%s" % item + raise ValueError + a = self.RPythonAnnotator() + s = a.build_types(f, []) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_no_nul_mod(self): def f(x): s = "%d" % x @@ -2133,6 +2231,14 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_no_nul_mod_unicode(self): + def f(x): + s = u"%d" % x + return s + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_mul_str0(self): def f(s): @@ -2142,6 +2248,24 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + + def test_reverse_mul_str0(self): + def f(s): + return 10*s + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeString) + assert s.no_nul + + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_getitem_str0(self): def f(s, n): if n == 1: @@ -2153,12 +2277,18 @@ return s a = self.RPythonAnnotator() a.translator.config.translation.check_str_without_nul = True - s = a.build_types(f, [annmodel.SomeString(no_nul=True), annmodel.SomeInteger()]) assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True), + annmodel.SomeInteger()]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_non_none_and_none_with_isinstance(self): class A(object): pass @@ -3411,6 +3541,7 @@ a = self.RPythonAnnotator() s = a.build_types(f, [unicode]) assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_unicode_char(self): def f(x, i): @@ -3916,6 +4047,19 @@ assert s.can_be_None assert s.no_nul + def test_contains_no_nul_unicode(self): + def f(i): + if u"\0" in i: + return None + else: + return i + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.can_be_None + assert s.no_nul + def test_no___call__(self): class X(object): def __call__(self): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -574,7 +574,9 @@ return self.basecharclass() def method_split(self, patt, max=-1): - if max == -1 and patt.is_constant() and patt.const == "\0": + # special-case for .split( '\x00') or .split(u'\x00') + if max == -1 and patt.is_constant() and ( + len(patt.const) == 1 and ord(patt.const) == 0): no_nul = True else: no_nul = self.no_nul diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -16,10 +16,11 @@ DEFL_GC = "incminimark" # XXX +DEFL_ROOTFINDER_WITHJIT = "shadowstack" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" -else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + _mach = os.popen('uname -m', 'r').read().strip() + if _mach.startswith('x86') or _mach in ['i386', 'i486', 'i586', 'i686']: + DEFL_ROOTFINDER_WITHJIT = "asmgcc" # only for Linux on x86 / x86-64 IS_64_BITS = sys.maxint > 2147483647 diff --git a/rpython/jit/backend/arm/test/support.py b/rpython/jit/backend/arm/test/support.py --- a/rpython/jit/backend/arm/test/support.py +++ b/rpython/jit/backend/arm/test/support.py @@ -10,7 +10,9 @@ class JitARMMixin(support.LLJitMixin): type_system = 'lltype' CPUClass = getcpuclass() - basic = True + # we have to disable unroll + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + basic = False def check_jumps(self, maxcount): pass diff --git a/rpython/jit/backend/arm/test/test_helper.py b/rpython/jit/backend/arm/test/test_helper.py --- a/rpython/jit/backend/arm/test/test_helper.py +++ b/rpython/jit/backend/arm/test/test_helper.py @@ -1,6 +1,8 @@ from rpython.jit.backend.arm.helper.assembler import count_reg_args -from rpython.jit.metainterp.history import (BoxInt, BoxPtr, BoxFloat, - INT, REF, FLOAT) +from rpython.jit.metainterp.history import INT, REF, FLOAT +from rpython.jit.metainterp.resoperation import InputArgInt as BoxInt +from rpython.jit.metainterp.resoperation import InputArgRef as BoxPtr +from rpython.jit.metainterp.resoperation import InputArgFloat as BoxFloat def test_count_reg_args(): diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py --- a/rpython/jit/backend/arm/test/test_regalloc.py +++ b/rpython/jit/backend/arm/test/test_regalloc.py @@ -215,14 +215,14 @@ def test_exception_bridge_no_exception(self): ops = ''' [i0] - i1 = same_as(1) - call(ConstClass(raising_fptr), i0, descr=raising_calldescr) + i1 = same_as_i(1) + call_n(ConstClass(raising_fptr), i0, descr=raising_calldescr) guard_exception(ConstClass(zero_division_error)) [i1] finish(0) ''' bridge_ops = ''' [i3] - i2 = same_as(2) + i2 = same_as_i(2) guard_no_exception() [i2] finish(1) ''' @@ -379,7 +379,7 @@ def test_bug_wrong_stack_adj(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - i9 = same_as(0) + i9 = same_as_i(0) guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -387,7 +387,7 @@ assert self.getint(0) == 0 bridge_ops = ''' [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] - call(ConstClass(raising_fptr), 0, descr=raising_calldescr) + call_n(ConstClass(raising_fptr), 0, descr=raising_calldescr) guard_true(i0) [i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -430,7 +430,7 @@ def test_cmp_op_0(self): ops = ''' [i0, i3] - i1 = same_as(1) + i1 = same_as_i(1) i2 = int_lt(i0, 100) guard_true(i3) [i1, i2] finish(i2) @@ -630,7 +630,7 @@ def test_one_call(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_true(i10), [i10, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -639,8 +639,8 @@ def test_two_calls(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) - i11 = call(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) + i11 = call_i(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) guard_true(i11) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -649,7 +649,7 @@ def test_call_many_arguments(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] - i8 = call(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) + i8 = call_i(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) finish(i8) ''' self.interpret(ops, [2, 3, 4, 5, 6, 7, 8, 9]) @@ -658,7 +658,7 @@ def test_bridge_calls_1(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i2 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_value(i2, 0, descr=fdescr1) [i2, i1] finish(i1) ''' @@ -666,7 +666,7 @@ assert self.getint(0) == 5 ops = ''' [i2, i1] - i3 = call(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) + i3 = call_i(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -677,7 +677,7 @@ def test_bridge_calls_2(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) + i2 = call_i(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) guard_value(i2, 0, descr=fdescr1) [i2] finish(i1) ''' @@ -685,7 +685,7 @@ assert self.getint(0) == 4 * 7 ops = ''' [i2] - i3 = call(ConstClass(f1ptr), i2, descr=f1_calldescr) + i3 = call_i(ConstClass(f1ptr), i2, descr=f1_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -734,7 +734,7 @@ loop2 = """ [i0] i1 = force_token() - i2 = call_assembler(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) + i2 = call_assembler_i(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) guard_not_forced() [i0] guard_false(i0) [i0, i2] """ @@ -749,23 +749,23 @@ label(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) i11 = int_add(i0, 1) i12 = int_lt(i11, 2) - i13 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i14 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i15 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i16 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i17 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i18 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i19 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i20 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i21 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i22 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i23 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i24 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i26 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i27 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i28 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i29 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i30 = call(ConstClass(f_fptr), i12, descr=f_calldescr) + i13 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i14 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i15 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i16 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i17 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i18 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i19 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i20 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i21 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i22 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i23 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i24 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i26 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i27 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i28 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i29 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i30 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) guard_true(i12) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] jump(i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) """ diff --git a/rpython/jit/backend/arm/test/test_regalloc2.py b/rpython/jit/backend/arm/test/test_regalloc2.py deleted file mode 100644 --- a/rpython/jit/backend/arm/test/test_regalloc2.py +++ /dev/null @@ -1,281 +0,0 @@ -import py -from rpython.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, BasicFailDescr, BasicFinalDescr -from rpython.jit.metainterp.history import JitCellToken -from rpython.jit.metainterp.resoperation import rop -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.backend.arm.arch import WORD -CPU = getcpuclass() - -def test_bug_rshift(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_ADD, [v1, v1], v2), - ResOperation(rop.INT_INVERT, [v2], v3), - ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(1)), - ] - operations[-2].setfailargs([v4, v3]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, 9) - assert cpu.get_int_value(deadframe, 0) == (9 >> 3) - assert cpu.get_int_value(deadframe, 1) == (~18) - -def test_bug_int_is_true_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - tmp5 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_MUL, [v1, v1], v2), - ResOperation(rop.INT_MUL, [v2, v1], v3), - ResOperation(rop.INT_IS_TRUE, [v2], tmp5), - ResOperation(rop.INT_IS_ZERO, [tmp5], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()), - ] - operations[-2].setfailargs([v4, v3, tmp5]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, -10) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == -1000 - assert cpu.get_int_value(deadframe, 2) == 1 - -def test_bug_0(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - tmp46 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_GT, [v3, ConstInt(-48)], v11), - ResOperation(rop.INT_XOR, [v8, v1], v12), - ResOperation(rop.INT_GT, [v6, ConstInt(-9)], v13), - ResOperation(rop.INT_LE, [v13, v2], v14), - ResOperation(rop.INT_LE, [v11, v5], v15), - ResOperation(rop.UINT_GE, [v13, v13], v16), - ResOperation(rop.INT_OR, [v9, ConstInt(-23)], v17), - ResOperation(rop.INT_LT, [v10, v13], v18), - ResOperation(rop.INT_OR, [v15, v5], v19), - ResOperation(rop.INT_XOR, [v17, ConstInt(54)], v20), - ResOperation(rop.INT_MUL, [v8, v10], v21), - ResOperation(rop.INT_OR, [v3, v9], v22), - ResOperation(rop.INT_AND, [v11, ConstInt(-4)], tmp41), - ResOperation(rop.INT_OR, [tmp41, ConstInt(1)], tmp42), - ResOperation(rop.INT_MOD, [v12, tmp42], v23), - ResOperation(rop.INT_IS_TRUE, [v6], v24), - ResOperation(rop.UINT_RSHIFT, [v15, ConstInt(6)], v25), - ResOperation(rop.INT_OR, [ConstInt(-4), v25], v26), - ResOperation(rop.INT_INVERT, [v8], v27), - ResOperation(rop.INT_SUB, [ConstInt(-113), v11], v28), - ResOperation(rop.INT_NEG, [v7], v29), - ResOperation(rop.INT_NEG, [v24], v30), - ResOperation(rop.INT_FLOORDIV, [v3, ConstInt(53)], v31), - ResOperation(rop.INT_MUL, [v28, v27], v32), - ResOperation(rop.INT_AND, [v18, ConstInt(-4)], tmp43), - ResOperation(rop.INT_OR, [tmp43, ConstInt(1)], tmp44), - ResOperation(rop.INT_MOD, [v26, tmp44], v33), - ResOperation(rop.INT_OR, [v27, v19], v34), - ResOperation(rop.UINT_LT, [v13, ConstInt(1)], v35), - ResOperation(rop.INT_AND, [v21, ConstInt(31)], tmp45), - ResOperation(rop.INT_RSHIFT, [v21, tmp45], v36), - ResOperation(rop.INT_AND, [v20, ConstInt(31)], tmp46), - ResOperation(rop.UINT_RSHIFT, [v4, tmp46], v37), - ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), - ResOperation(rop.INT_NEG, [v7], v39), - ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ] - operations[-1].setfailargs([v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - args = [-13 , 10 , 10 , 8 , -8 , -16 , -18 , 46 , -12 , 26] - deadframe = cpu.execute_token(looptoken, *args) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 0 - assert cpu.get_int_value(deadframe, 2) == 0 - assert cpu.get_int_value(deadframe, 3) == 0 - assert cpu.get_int_value(deadframe, 4) == 1 - assert cpu.get_int_value(deadframe, 5) == -7 - assert cpu.get_int_value(deadframe, 6) == 1 - assert cpu.get_int_value(deadframe, 7) == 0 - assert cpu.get_int_value(deadframe, 8) == -2 - assert cpu.get_int_value(deadframe, 9) == 18 - assert cpu.get_int_value(deadframe, 10) == 1 - assert cpu.get_int_value(deadframe, 11) == 18 - assert cpu.get_int_value(deadframe, 12) == -1 - assert cpu.get_int_value(deadframe, 13) == 0 - -def test_bug_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_LT, [v6, ConstInt(0)], v11), - ResOperation(rop.INT_AND, [v3, ConstInt(31)], tmp41), - ResOperation(rop.INT_RSHIFT, [v3, tmp41], v12), - ResOperation(rop.INT_NEG, [v2], v13), - ResOperation(rop.INT_ADD, [v11, v7], v14), - ResOperation(rop.INT_OR, [v3, v2], v15), - ResOperation(rop.INT_OR, [v12, v12], v16), - ResOperation(rop.INT_NE, [v2, v5], v17), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp42), - ResOperation(rop.UINT_RSHIFT, [v14, tmp42], v18), - ResOperation(rop.INT_AND, [v14, ConstInt(31)], tmp43), - ResOperation(rop.INT_LSHIFT, [ConstInt(7), tmp43], v19), - ResOperation(rop.INT_NEG, [v19], v20), - ResOperation(rop.INT_MOD, [v3, ConstInt(1)], v21), - ResOperation(rop.UINT_GE, [v15, v1], v22), - ResOperation(rop.INT_AND, [v16, ConstInt(31)], tmp44), - ResOperation(rop.INT_LSHIFT, [v8, tmp44], v23), - ResOperation(rop.INT_IS_TRUE, [v17], v24), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp45), - ResOperation(rop.INT_LSHIFT, [v14, tmp45], v25), - ResOperation(rop.INT_LSHIFT, [v5, ConstInt(17)], v26), - ResOperation(rop.INT_EQ, [v9, v15], v27), - ResOperation(rop.INT_GE, [ConstInt(0), v6], v28), - ResOperation(rop.INT_NEG, [v15], v29), - ResOperation(rop.INT_NEG, [v22], v30), - ResOperation(rop.INT_ADD, [v7, v16], v31), - ResOperation(rop.UINT_LT, [v19, v19], v32), - ResOperation(rop.INT_ADD, [v2, ConstInt(1)], v33), - ResOperation(rop.INT_NEG, [v5], v34), - ResOperation(rop.INT_ADD, [v17, v24], v35), - ResOperation(rop.UINT_LT, [ConstInt(2), v16], v36), - ResOperation(rop.INT_NEG, [v9], v37), - ResOperation(rop.INT_GT, [v4, v11], v38), - ResOperation(rop.INT_LT, [v27, v22], v39), - ResOperation(rop.INT_NEG, [v27], v40), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ] - operations[-1].setfailargs([v40, v10, v36, v26, v13, v30, v21, v33, v18, v25, v31, v32, v28, v29, v35, v38, v20, v39, v34, v23, v37]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - args = [17 , -20 , -6 , 6 , 1 , 13 , 13 , 9 , 49 , 8] - deadframe = cpu.execute_token(looptoken, *args) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 8 - assert cpu.get_int_value(deadframe, 2) == 1 - assert cpu.get_int_value(deadframe, 3) == 131072 - assert cpu.get_int_value(deadframe, 4) == 20 - assert cpu.get_int_value(deadframe, 5) == -1 - assert cpu.get_int_value(deadframe, 6) == 0 - assert cpu.get_int_value(deadframe, 7) == -19 - assert cpu.get_int_value(deadframe, 8) == 6 - assert cpu.get_int_value(deadframe, 9) == 26 - assert cpu.get_int_value(deadframe, 10) == 12 - assert cpu.get_int_value(deadframe, 11) == 0 - assert cpu.get_int_value(deadframe, 12) == 0 - assert cpu.get_int_value(deadframe, 13) == 2 - assert cpu.get_int_value(deadframe, 14) == 2 - assert cpu.get_int_value(deadframe, 15) == 1 - assert cpu.get_int_value(deadframe, 16) == -57344 - assert cpu.get_int_value(deadframe, 17) == 1 - assert cpu.get_int_value(deadframe, 18) == -1 - if WORD == 4: - assert cpu.get_int_value(deadframe, 19) == -2147483648 - elif WORD == 8: - assert cpu.get_int_value(deadframe, 19) == 19327352832 - assert cpu.get_int_value(deadframe, 20) == -49 diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -80,8 +80,8 @@ self.gc_size_of_header = gc_ll_descr.gcheaderbuilder.size_gc_header else: self.gc_size_of_header = WORD # for tests - self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn) - self.memset_addr = self.cpu.cast_ptr_to_int(memset_fn) + self.memcpy_addr = rffi.cast(lltype.Signed, memcpy_fn) + self.memset_addr = rffi.cast(lltype.Signed, memset_fn) self._build_failure_recovery(False, withfloats=False) self._build_failure_recovery(True, withfloats=False) self._build_wb_slowpath(False) diff --git a/rpython/jit/backend/llsupport/codemap.py b/rpython/jit/backend/llsupport/codemap.py --- a/rpython/jit/backend/llsupport/codemap.py +++ b/rpython/jit/backend/llsupport/codemap.py @@ -15,7 +15,7 @@ from rpython.rlib.entrypoint import jit_entrypoint from rpython.rlib.rbisect import bisect_right, bisect_right_addr from rpython.rlib.rbisect import bisect_left, bisect_left_addr -from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.translator import cdir @@ -74,11 +74,12 @@ stack_depth_at_loc = llexternal('pypy_jit_stack_depth_at_loc', [lltype.Signed], lltype.Signed) find_codemap_at_addr = llexternal('pypy_find_codemap_at_addr', - [lltype.Signed, rffi.CArrayPtr(lltype.Signed)], lltype.Signed) + [lltype.Signed, rffi.CArrayPtr(lltype.Signed)], + llmemory.Address) yield_bytecode_at_addr = llexternal('pypy_yield_codemap_at_addr', - [lltype.Signed, lltype.Signed, + [llmemory.Address, lltype.Signed, rffi.CArrayPtr(lltype.Signed)], - lltype.Signed) + lltype.Signed) class CodemapStorage(object): diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -600,16 +600,22 @@ @specialize.argtype(1) def bh_getfield_gc_i(self, struct, fielddescr): ofs, size, sign = self.unpack_fielddescr_size(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_int_at_mem(struct, ofs, size, sign) @specialize.argtype(1) def bh_getfield_gc_r(self, struct, fielddescr): ofs = self.unpack_fielddescr(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_ref_at_mem(struct, ofs) @specialize.argtype(1) def bh_getfield_gc_f(self, struct, fielddescr): ofs = self.unpack_fielddescr(fielddescr) + if isinstance(lltype.typeOf(struct), lltype.Ptr): + fielddescr.check_correct_type(struct) return self.read_float_at_mem(struct, ofs) bh_getfield_raw_i = bh_getfield_gc_i diff --git a/rpython/jit/backend/test/calling_convention_test.py b/rpython/jit/backend/test/calling_convention_test.py --- a/rpython/jit/backend/test/calling_convention_test.py +++ b/rpython/jit/backend/test/calling_convention_test.py @@ -152,6 +152,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) + res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001 def test_call_aligned_with_args_on_the_stack(self): @@ -194,6 +195,7 @@ res = self.execute_operation(rop.CALL_F, [funcbox] + argslist, 'float', descr=calldescr) + res = longlong.getrealfloat(res) assert abs(res - result) < 0.0001 def test_call_alignment_call_assembler(self): diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2293,6 +2293,7 @@ func_ptr = llhelper(lltype.Ptr(FUNC), func_void) calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) + gfs = longlong.getfloatstorage for (operation, arg1, arg2_if_true, arg2_if_false) in [ ('int_lt', -5, 2, -5), @@ -2303,8 +2304,8 @@ ('int_xor', 7, 3, 7), # test without a comparison at all ('int_is_true', 4242, 1, 0), ('int_is_zero', 4242, 0, 1), - ('float_lt', -0.5, 0.2, -0.5), - ('float_eq', 1.1, 1.1, 1.2), + ('float_lt', gfs(-0.5), gfs(0.2), gfs(-0.5)), + ('float_eq', gfs(1.1), gfs(1.1), gfs(1.2)), ]: called = [] @@ -3788,10 +3789,61 @@ assert called == [finish_descr] del called[:] - # compile a replacement + # compile a replacement which needs more jitframe stack space ops = ''' [f0, f1] f2 = float_sub(f0, f1) + f3 = float_sub(f0, f1) + f4 = float_sub(f0, f1) + f5 = float_sub(f0, f1) + f6 = float_sub(f0, f1) + f7 = float_sub(f0, f1) + f8 = float_sub(f0, f1) + f9 = float_sub(f0, f1) + f10 = float_sub(f0, f1) + f11 = float_sub(f0, f1) + f12 = float_sub(f0, f1) + f13 = float_sub(f0, f1) + f14 = float_sub(f0, f1) + f15 = float_sub(f0, f1) + f16 = float_sub(f0, f1) + f17 = float_sub(f0, f1) + f18 = float_sub(f0, f1) + f19 = float_sub(f0, f1) + i3 = float_eq(f2, f3) + i4 = float_eq(f2, f4) + i5 = float_eq(f2, f5) + i6 = float_eq(f2, f6) + i7 = float_eq(f2, f7) + i8 = float_eq(f2, f8) + i9 = float_eq(f2, f9) + i10 = float_eq(f2, f10) + i11 = float_eq(f2, f11) + i12 = float_eq(f2, f12) + i13 = float_eq(f2, f13) + i14 = float_eq(f2, f14) + i15 = float_eq(f2, f15) + i16 = float_eq(f2, f16) + i17 = float_eq(f2, f17) + i18 = float_eq(f2, f18) + i19 = float_eq(f2, f19) + guard_true(i3) [] + guard_true(i4) [] + guard_true(i5) [] + guard_true(i6) [] + guard_true(i7) [] + guard_true(i8) [] + guard_true(i9) [] + guard_true(i10) [] + guard_true(i11) [] + guard_true(i12) [] + guard_true(i13) [] + guard_true(i14) [] + guard_true(i15) [] + guard_true(i16) [] + guard_true(i17) [] + guard_true(i18) [] + guard_true(i19) [] finish(f2)''' loop2 = parse(ops) looptoken2 = JitCellToken() @@ -3799,9 +3851,21 @@ self.cpu.compile_loop(loop2.inputargs, loop2.operations, looptoken2) finish_descr2 = loop2.operations[-1].getdescr() + # check the jitframeinfo + if isinstance(self.cpu, AbstractLLCPU): + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 < num2 + # install it self.cpu.redirect_call_assembler(looptoken, looptoken2) + # check that the jitframeinfo was updated + if isinstance(self.cpu, AbstractLLCPU): + num1 = looptoken.compiled_loop_token.frame_info.jfi_frame_depth + num2 = looptoken2.compiled_loop_token.frame_info.jfi_frame_depth + assert num1 == num2 + # now, our call_assembler should go to looptoken2 args = [longlong.getfloatstorage(6.0), longlong.getfloatstorage(1.5)] # 6.0-1.5 == 1.25+3.25 @@ -5000,3 +5064,56 @@ ]: self.execute_operation(rop.GUARD_SUBCLASS, [arg, klass], 'void') assert self.guard_failed == (not is_subclass) + + def test_bug_from_optimize_cond_call(self): + loop = parse(""" + [i0, i1] + i99 = int_sub(i0, i0) + force_spill(i99) + i2 = int_add(i0, i1) + i3 = int_add(i0, i1) + i4 = int_add(i0, i1) + i5 = int_add(i0, i1) + i6 = int_add(i0, i1) + i7 = int_add(i0, i1) + i8 = int_add(i0, i1) + i9 = int_add(i0, i1) + i10 = int_add(i0, i1) + i11 = int_add(i0, i1) + i12 = int_add(i0, i1) + i13 = int_add(i0, i1) + i14 = int_add(i0, i1) + i15 = int_add(i0, i1) + i16 = int_add(i0, i1) + i17 = int_add(i0, i1) + i18 = int_add(i0, i1) + i19 = int_add(i0, i1) + i20 = int_is_true(i99) + force_spill(i0) + force_spill(i1) + force_spill(i2) + force_spill(i3) + force_spill(i4) + force_spill(i5) + force_spill(i6) + force_spill(i7) + force_spill(i8) + force_spill(i9) + force_spill(i10) + force_spill(i11) + force_spill(i12) + force_spill(i13) + force_spill(i14) + force_spill(i15) + force_spill(i16) + force_spill(i17) + force_spill(i18) + force_spill(i19) + finish(i20, descr=finaldescr) + """, namespace={"finaldescr": BasicFinalDescr(1)}) + looptoken = JitCellToken() + self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) + deadframe = self.cpu.execute_token(looptoken, 40, 2) + fail = self.cpu.get_latest_descr(deadframe) + res = self.cpu.get_int_value(deadframe, 0) + assert res == 0 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -175,12 +175,12 @@ for i in range(4): mc.MOV_sr(i * WORD, cond_call_register_arguments[i].value) mc.CALL(eax) + self._reload_frame_if_necessary(mc) if IS_X86_64: mc.ADD(esp, imm(WORD)) else: mc.ADD(esp, imm(WORD * 7)) self.set_extra_stack_depth(mc, 0) - self._reload_frame_if_necessary(mc, align_stack=True) self.pop_gcmap(mc) # cancel the push_gcmap(store=True) in the caller self._pop_all_regs_from_frame(mc, [], supports_floats, callee_only) mc.RET() @@ -244,14 +244,15 @@ mc.MOV_rs(edi.value, WORD * 3) # load the itemsize self.set_extra_stack_depth(mc, 16) mc.CALL(imm(follow_jump(addr))) + self._reload_frame_if_necessary(mc) mc.ADD_ri(esp.value, 16 - WORD) + self.set_extra_stack_depth(mc, 0) + # mc.TEST_rr(eax.value, eax.value) From noreply at buildbot.pypy.org Tue Sep 22 11:10:09 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:10:09 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: whack at pyjitpl until the first overflow test passes Message-ID: <20150922091009.832351C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79751:a139878f9977 Date: 2015-09-22 11:10 +0200 http://bitbucket.org/pypy/pypy/changeset/a139878f9977/ Log: whack at pyjitpl until the first overflow test passes 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 @@ -238,7 +238,8 @@ resbox = self.execute(rop.%s, b1, b2) self.make_result_of_lastop(resbox) # same as execute_varargs() if not isinstance(resbox, Const): - self.metainterp.handle_possible_overflow_error(lbl, orgpc) + return self.handle_possible_overflow_error(lbl, orgpc, + resbox) return resbox ''' % (_opimpl, resop)).compile() @@ -1459,6 +1460,17 @@ def setup_resume_at_op(self, pc): self.pc = pc + def handle_possible_overflow_error(self, label, orgpc, resbox): + if self.metainterp.ovf_flag: + self.metainterp.generate_guard(rop.GUARD_OVERFLOW, None, + resumepc=orgpc) + self.pc = label + return None + else: + self.metainterp.generate_guard(rop.GUARD_NO_OVERFLOW, None, + resumepc=orgpc) + return resbox + def run_one_step(self): # Execute the frame forward. This method contains a loop that leaves # whenever the 'opcode_implementations' (which is one of the 'opimpl_' @@ -2024,8 +2036,7 @@ else: moreargs = list(extraargs) if opnum == rop.GUARD_EXCEPTION: - guard_op = self.history.record(opnum, moreargs, - lltype.nullptr(llmemory.GCREF.TO)) + guard_op = self.history.record(opnum, moreargs, None) else: guard_op = self.history.record(opnum, moreargs, None) assert isinstance(guard_op, GuardResOp) @@ -2746,13 +2757,6 @@ else: self.generate_guard(rop.GUARD_NO_EXCEPTION, None, []) - def handle_possible_overflow_error(self, label, orgpc): - if self.ovf_flag: - self.generate_guard(rop.GUARD_OVERFLOW, None, resumepc=orgpc) - self.pc = label - else: - self.generate_guard(rop.GUARD_NO_OVERFLOW, None, resumepc=orgpc) - def assert_no_exception(self): assert not self.last_exc_value @@ -3202,16 +3206,17 @@ print '-> %r' % (resultbox,) assert argcodes[next_argcode] == '>' result_argcode = argcodes[next_argcode + 1] - assert resultbox.type == {'i': history.INT, - 'r': history.REF, - 'f': history.FLOAT}[result_argcode] + if 'ovf' not in name: + assert resultbox.type == {'i': history.INT, + 'r': history.REF, + 'f': history.FLOAT}[result_argcode] else: resultbox = unboundmethod(self, *args) # if resultbox is not None: self.make_result_of_lastop(resultbox) elif not we_are_translated(): - assert self._result_argcode in 'v?' + assert self._result_argcode in 'v?' or 'ovf' in name # unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func argtypes = unrolling_iterable(unboundmethod.argtypes) From noreply at buildbot.pypy.org Tue Sep 22 11:12:00 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:12:00 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: commited one thing too many Message-ID: <20150922091200.517C31C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79752:ff1de0c031e8 Date: 2015-09-22 11:11 +0200 http://bitbucket.org/pypy/pypy/changeset/ff1de0c031e8/ Log: commited one thing too many 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 @@ -2036,7 +2036,8 @@ else: moreargs = list(extraargs) if opnum == rop.GUARD_EXCEPTION: - guard_op = self.history.record(opnum, moreargs, None) + guard_op = self.history.record(opnum, moreargs, + lltype.nullptr(llmemory.GCREF.TO)) else: guard_op = self.history.record(opnum, moreargs, None) assert isinstance(guard_op, GuardResOp) From noreply at buildbot.pypy.org Tue Sep 22 11:34:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:34:12 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: more overflow implementations in blackhole Message-ID: <20150922093412.B341F1C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79753:19ab0b0ba9bb Date: 2015-09-22 11:14 +0200 http://bitbucket.org/pypy/pypy/changeset/19ab0b0ba9bb/ Log: more overflow implementations in blackhole 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 @@ -408,13 +408,19 @@ def bhimpl_int_mul(a, b): return intmask(a * b) - @arguments("i", "i", returns="i") - def bhimpl_int_add_ovf(a, b): - return ovfcheck(a + b) + @arguments("L", "i", "i", returns="iL") + def bhimpl_int_add_jump_if_ovf(label, a, b): + try: + return ovfcheck(a + b), -1 + except OverflowError: + return 0, label - @arguments("i", "i", returns="i") - def bhimpl_int_sub_ovf(a, b): - return ovfcheck(a - b) + @arguments("L", "i", "i", returns="iL") + def bhimpl_int_sub_jump_if_ovf(label, a, b): + try: + return ovfcheck(a - b), -1 + except OverflowError: + return 0, label @arguments("L", "i", "i", returns="iL") def bhimpl_int_mul_jump_if_ovf(label, a, b): From noreply at buildbot.pypy.org Tue Sep 22 11:34:14 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:34:14 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix some tests Message-ID: <20150922093414.CFED81C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79754:2ffbdb25990c Date: 2015-09-22 11:27 +0200 http://bitbucket.org/pypy/pypy/changeset/2ffbdb25990c/ Log: fix some tests diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -401,7 +401,7 @@ r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op) raise InvalidLoop('A GUARD_VALUE (%s) was proven to ' 'always fail' % r) - descr = compile.ResumeGuardValueDescr() + descr = compile.ResumeGuardDescr() op = old_guard_op.copy_and_change(rop.GUARD_VALUE, args = [old_guard_op.getarg(0), op.getarg(1)], descr = descr) @@ -453,7 +453,7 @@ if old_guard_op.getopnum() == rop.GUARD_NONNULL: # it was a guard_nonnull, which we replace with a # guard_nonnull_class. - descr = compile.ResumeGuardNonnullClassDescr() + descr = compile.ResumeGuardDescr() op = old_guard_op.copy_and_change (rop.GUARD_NONNULL_CLASS, args = [old_guard_op.getarg(0), op.getarg(1)], descr=descr) 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 @@ -2628,7 +2628,10 @@ node2.val = 7 if a >= 100: sa += 1 - sa += ovfcheck(i + i) + try: + sa += ovfcheck(i + i) + except OverflowError: + assert 0 node1 = A(i) i += 1 assert self.meta_interp(f, [20, 7]) == f(20, 7) @@ -3898,7 +3901,6 @@ def dec(self): return Int(self.a - 1) - class Float(Base): def __init__(self, a): self.a = a From noreply at buildbot.pypy.org Tue Sep 22 11:34:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:34:17 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: skip tagging test Message-ID: <20150922093417.203961C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79755:25206e1319d6 Date: 2015-09-22 11:27 +0200 http://bitbucket.org/pypy/pypy/changeset/25206e1319d6/ Log: skip tagging test 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 @@ -3888,6 +3888,7 @@ class TestLLtype(BaseLLtypeTests, LLJitMixin): def test_tagged(self): + py.test.skip("I don't want to care right now") from rpython.rlib.objectmodel import UnboxedValue class Base(object): __slots__ = () From noreply at buildbot.pypy.org Tue Sep 22 11:34:19 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:34:19 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix flatten.py for the common case Message-ID: <20150922093419.2FA281C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79756:e7b232b9edd9 Date: 2015-09-22 11:31 +0200 http://bitbucket.org/pypy/pypy/changeset/e7b232b9edd9/ Log: fix flatten.py for the common case diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py --- a/rpython/jit/codewriter/flatten.py +++ b/rpython/jit/codewriter/flatten.py @@ -118,7 +118,7 @@ operations = block.operations for i, op in enumerate(operations): if '_ovf' in op.opname: - if (len(block.exits) != 2 or + if (len(block.exits) not in (2, 3) or block.exitswitch is not c_last_exception): raise Exception("detected a block containing ovfcheck()" " but no OverflowError is caught, this" @@ -194,10 +194,13 @@ line = self.popline() self.emitline(opname[:7] + '_jump_if_ovf', TLabel(block.exits[1]), *line[1:]) - assert len(block.exits) == 2 + assert len(block.exits) in (2, 3) self.make_link(block.exits[0], False) self.emitline(Label(block.exits[1])) self.make_exception_link(block.exits[1], True) + if len(block.exits) == 3: + assert block.exits[2].exitcase is Exception + self.make_exception_link(block.exits[2], False) return else: while True: From noreply at buildbot.pypy.org Tue Sep 22 11:34:21 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:34:21 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: a test showing a problem Message-ID: <20150922093421.403F71C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79757:b45541d0b3af Date: 2015-09-22 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/b45541d0b3af/ Log: a test showing a problem 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 @@ -889,6 +889,24 @@ res = self.interp_operations(f, [1, sys.maxint]) assert res == -42 + def test_ovf_raise(self): + def g(x, y): + try: + return ovfcheck(x * y) + except OverflowError: + raise + + def f(x, y): + try: + return g(x, y) + except OverflowError: + return 3 + + res = self.interp_operations(f, [sys.maxint, 2]) + assert res == 3 + res = self.interp_operations(f, [3, 2]) + assert res == 6 + def test_int_sub_ovf(self): def f(x, y): try: @@ -3888,7 +3906,6 @@ class TestLLtype(BaseLLtypeTests, LLJitMixin): def test_tagged(self): - py.test.skip("I don't want to care right now") from rpython.rlib.objectmodel import UnboxedValue class Base(object): __slots__ = () @@ -3900,7 +3917,10 @@ return self.a > 0 def dec(self): - return Int(self.a - 1) + try: + return Int(self.a - 1) + except OverflowError: + raise class Float(Base): def __init__(self, a): From noreply at buildbot.pypy.org Tue Sep 22 11:38:56 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:38:56 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix (arigo) Message-ID: <20150922093856.3EA491C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79758:0a9f22ba087f Date: 2015-09-22 11:38 +0200 http://bitbucket.org/pypy/pypy/changeset/0a9f22ba087f/ Log: fix (arigo) diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py --- a/rpython/jit/codewriter/flatten.py +++ b/rpython/jit/codewriter/flatten.py @@ -166,7 +166,7 @@ exc_data = self.cpu.rtyper.exceptiondata ll_ovf = exc_data.get_standard_ll_exc_instance_by_class( OverflowError) - c = Constant(ll_ovf, concretetype=lltype.Void) + c = Constant(ll_ovf, concretetype=lltype.typeOf(ll_ovf)) self.emitline("raise", c) else: self.emitline("reraise") From noreply at buildbot.pypy.org Tue Sep 22 11:40:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:40:13 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: skip this test Message-ID: <20150922094013.E057C1C01DE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79759:4b585aa28387 Date: 2015-09-22 11:40 +0200 http://bitbucket.org/pypy/pypy/changeset/4b585aa28387/ Log: skip this test 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 @@ -3906,6 +3906,7 @@ class TestLLtype(BaseLLtypeTests, LLJitMixin): def test_tagged(self): + py.test.skip("tagged unsupported") from rpython.rlib.objectmodel import UnboxedValue class Base(object): __slots__ = () From noreply at buildbot.pypy.org Tue Sep 22 11:44:20 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 11:44:20 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: don't share across potentially raising call_pure Message-ID: <20150922094420.88D591C01DE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79760:22755212f028 Date: 2015-09-22 11:44 +0200 http://bitbucket.org/pypy/pypy/changeset/22755212f028/ Log: don't share across potentially raising call_pure 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 @@ -587,7 +587,8 @@ op = self.emit_guard_operation(op, pendingfields) elif op.can_raise(): self.exception_might_have_happened = True - if op.has_no_side_effect() or op.is_guard() or op.is_jit_debug(): + if (op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() and + not self.is_call_pure_pure_canraise(op)): pass else: self._last_guard_op = None @@ -602,7 +603,6 @@ self._last_guard_op) else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) - #if op.getopnum() not in (rop.GUARD_EXCEPTION, rop.GUARD_OVERFLOW): self._last_guard_op = op # for unrolling for farg in op.getfailargs(): @@ -627,6 +627,14 @@ def getlastop(self): return self._really_emitted_operation + def is_call_pure_pure_canraise(self, op): + if not op.is_call_pure(): + return False + effectinfo = op.getdescr().get_extra_info() + if effectinfo.check_can_raise(ignore_memoryerror=True): + return True + return False + def replace_guard_op(self, old_op_pos, new_op): old_op = self._newoperations[old_op_pos] assert old_op.is_guard() From noreply at buildbot.pypy.org Tue Sep 22 12:49:29 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 12:49:29 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: don't look into guard_exception for now Message-ID: <20150922104929.2EB4D1C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79761:c167bc541cbb Date: 2015-09-22 12:48 +0200 http://bitbucket.org/pypy/pypy/changeset/c167bc541cbb/ Log: don't look into guard_exception for now diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -847,6 +847,9 @@ assert 0, box.type self.status = ty | (r_uint(i) << self.ST_SHIFT) +class ResumeGuardExcDescr(ResumeGuardDescr): + pass + class ResumeAtPositionDescr(ResumeGuardDescr): pass @@ -934,6 +937,8 @@ elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE): # note - this only happens in tests resumedescr = ResumeAtPositionDescr() + elif opnum in (rop.GUARD_EXCEPTION, rop.GUARD_NO_EXCEPTION): + resumedescr = ResumeGuardExcDescr() else: resumedescr = ResumeGuardDescr() return resumedescr 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 @@ -603,7 +603,8 @@ self._last_guard_op) else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) - self._last_guard_op = op + if op.getopnum() != rop.GUARD_EXCEPTION: + self._last_guard_op = op # for unrolling for farg in op.getfailargs(): if farg: @@ -612,6 +613,8 @@ def _copy_resume_data_from(self, guard_op, last_guard_op): + if guard_op.getopnum() in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION): + assert last_guard_op.getopnum() == rop.GUARD_NOT_FORCED descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self) descr.copy_all_attributes_from(last_guard_op.getdescr()) guard_op.setdescr(descr) 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 @@ -2322,7 +2322,7 @@ if isinstance(key, compile.ResumeAtPositionDescr): self.seen_loop_header_for_jdindex = self.jitdriver_sd.index try: - self.prepare_resume_from_failure(deadframe) + self.prepare_resume_from_failure(deadframe, key) if self.resumekey_original_loop_token is None: # very rare case raise SwitchToBlackhole(Counters.ABORT_BRIDGE) self.interpret() @@ -2465,17 +2465,20 @@ else: assert 0 self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args) - def prepare_resume_from_failure(self, deadframe): + def prepare_resume_from_failure(self, deadframe, resumedescr): exception = self.cpu.grab_exc_value(deadframe) - if exception: - self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, - exception)) - #else: - # self.clear_exception() - #try: - # self.handle_possible_exception() - #except ChangeFrame: - # pass + if isinstance(resumedescr, compile.ResumeGuardExcDescr): + if exception: + self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, + exception)) + else: + self.clear_exception() + try: + self.handle_possible_exception() + except ChangeFrame: + pass + else: + assert not exception def get_procedure_token(self, greenkey, with_compiled_targets=False): JitCell = self.jitdriver_sd.warmstate.JitCell From noreply at buildbot.pypy.org Tue Sep 22 12:49:31 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 12:49:31 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix the test Message-ID: <20150922104931.5364C1C043B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79762:e56f2700a729 Date: 2015-09-22 12:49 +0200 http://bitbucket.org/pypy/pypy/changeset/e56f2700a729/ Log: fix the test diff --git a/rpython/jit/metainterp/test/test_exception.py b/rpython/jit/metainterp/test/test_exception.py --- a/rpython/jit/metainterp/test/test_exception.py +++ b/rpython/jit/metainterp/test/test_exception.py @@ -554,7 +554,10 @@ def test_overflowerror_escapes(self): def g(x): - return ovfcheck(x + 1) + try: + return ovfcheck(x + 1) + except OverflowError: + raise def f(x): try: return g(x) From noreply at buildbot.pypy.org Tue Sep 22 13:01:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 13:01:17 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: no sharing across guard_exception Message-ID: <20150922110117.62CCE1C0557@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79763:1f99b59fd373 Date: 2015-09-22 13:01 +0200 http://bitbucket.org/pypy/pypy/changeset/1f99b59fd373/ Log: no sharing across guard_exception 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 @@ -603,12 +603,13 @@ self._last_guard_op) else: op = self.store_final_boxes_in_guard(guard_op, pendingfields) - if op.getopnum() != rop.GUARD_EXCEPTION: - self._last_guard_op = op + self._last_guard_op = op # for unrolling for farg in op.getfailargs(): if farg: self.force_box(farg) + if op.getopnum() == rop.GUARD_EXCEPTION: + self._last_guard_op = None return op From noreply at buildbot.pypy.org Tue Sep 22 13:31:01 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 13:31:01 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix folding Message-ID: <20150922113101.B1EB21C0710@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79764:cebda0c1b84e Date: 2015-09-22 13:31 +0200 http://bitbucket.org/pypy/pypy/changeset/cebda0c1b84e/ Log: fix folding diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -251,7 +251,6 @@ b = box2.getint() try: z = ovfcheck(a + b) - metainterp.ovf_flag = False except OverflowError: assert metainterp is not None metainterp.ovf_flag = True @@ -263,7 +262,6 @@ b = box2.getint() try: z = ovfcheck(a - b) - metainterp.ovf_flag = False except OverflowError: assert metainterp is not None metainterp.ovf_flag = True @@ -275,7 +273,6 @@ b = box2.getint() try: z = ovfcheck(a * b) - metainterp.ovf_flag = False except OverflowError: assert metainterp is not None metainterp.ovf_flag = True 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 @@ -235,11 +235,15 @@ exec py.code.Source(''' @arguments("label", "box", "box", "orgpc") def opimpl_%s(self, lbl, b1, b2, orgpc): + self.metainterp.ovf_flag = False resbox = self.execute(rop.%s, b1, b2) self.make_result_of_lastop(resbox) # same as execute_varargs() if not isinstance(resbox, Const): return self.handle_possible_overflow_error(lbl, orgpc, resbox) + elif self.metainterp.ovf_flag: + self.pc = lbl + return None # but don't emit GUARD_OVERFLOW return resbox ''' % (_opimpl, resop)).compile() From noreply at buildbot.pypy.org Tue Sep 22 13:46:47 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 13:46:47 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: make this jittable Message-ID: <20150922114648.003BF1C01DE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79765:39aeb22ce4c4 Date: 2015-09-22 13:46 +0200 http://bitbucket.org/pypy/pypy/changeset/39aeb22ce4c4/ Log: make this jittable diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py --- a/pypy/objspace/std/intobject.py +++ b/pypy/objspace/std/intobject.py @@ -249,11 +249,17 @@ ix = 1 while iw > 0: if iw & 1: - ix = ovfcheck(ix * temp) + try: + ix = ovfcheck(ix * temp) + except OverflowError: + raise iw >>= 1 # Shift exponent down by 1 bit if iw == 0: break - temp = ovfcheck(temp * temp) # Square the value of temp + try: + temp = ovfcheck(temp * temp) # Square the value of temp + except OverflowError: + raise if iz: # If we did a multiplication, perform a modulo ix %= iz From noreply at buildbot.pypy.org Tue Sep 22 14:10:50 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 14:10:50 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix tests Message-ID: <20150922121050.3AFD31C05CE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79766:7a0ce841e389 Date: 2015-09-22 13:49 +0200 http://bitbucket.org/pypy/pypy/changeset/7a0ce841e389/ Log: fix tests 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 @@ -2502,7 +2502,6 @@ if values is not None: fail_args = values fdescr = guard_op.getdescr() - assert fdescr.guard_opnum == guard_opnum reader = ResumeDataFakeReader(fdescr, fail_args, MyMetaInterp(self.cpu)) boxes = reader.consume_boxes() From noreply at buildbot.pypy.org Tue Sep 22 14:10:52 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 14:10:52 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: rookie mistake on using is on integers, also fix some tests and reenable removing guards Message-ID: <20150922121052.8F1CD1C05CE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79767:91e6f52d365c Date: 2015-09-22 14:10 +0200 http://bitbucket.org/pypy/pypy/changeset/91e6f52d365c/ Log: rookie mistake on using is on integers, also fix some tests and reenable removing guards 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 @@ -567,15 +567,13 @@ self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if op.is_guard(): assert isinstance(op, GuardResOp) - #if self.origin_jitcode is not None: - # if (self.origin_jitcode is op.rd_frame_info_list.jitcode and - # self.origin_pc is op.rd_frame_info_list.pc): - # self.origin_jitcode = None - # self.origin_pc = 0 - # else: - # import pdb - # pdb.set_trace() - # return # we optimize the guard + if self.origin_jitcode is not None: + if (self.origin_jitcode is op.rd_frame_info_list.jitcode and + self.origin_pc == op.rd_frame_info_list.pc): + self.origin_jitcode = None + self.origin_pc = 0 + else: + return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None @@ -587,10 +585,12 @@ op = self.emit_guard_operation(op, pendingfields) elif op.can_raise(): self.exception_might_have_happened = True - if (op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() and + if ((op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() or + op.is_ovf()) and not self.is_call_pure_pure_canraise(op)): pass else: + assert self.origin_jitcode is None self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) 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 @@ -2082,7 +2082,7 @@ assert res == 7068153 self.check_trace_count(6) self.check_resops(guard_true=8, guard_class=2, int_mul=3, - int_add=3, guard_false=4) + int_add=3, guard_false=3) def test_dont_trace_every_iteration(self): myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa']) From noreply at buildbot.pypy.org Tue Sep 22 14:20:03 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 22 Sep 2015 14:20:03 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: disable the assert we might have setfields from virtuals that are "safe" Message-ID: <20150922122003.900941C05CE@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79768:c1c924a52508 Date: 2015-09-22 14:19 +0200 http://bitbucket.org/pypy/pypy/changeset/c1c924a52508/ Log: disable the assert we might have setfields from virtuals that are "safe" 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 @@ -590,7 +590,7 @@ not self.is_call_pure_pure_canraise(op)): pass else: - assert self.origin_jitcode is None + #assert self.origin_jitcode is None self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) From noreply at buildbot.pypy.org Tue Sep 22 15:16:35 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 15:16:35 +0200 (CEST) Subject: [pypy-commit] buildbot default: Run py3.3 nightly instead of py3k Message-ID: <20150922131635.217D31C1C61@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r962:0371f3d2234a Date: 2015-09-22 15:17 +0200 http://bitbucket.org/pypy/buildbot/changeset/0371f3d2234a/ Log: Run py3.3 nightly instead of py3k diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -286,10 +286,10 @@ NUMPY_WIN, # on allegro_win32, SalsaSalsa ]), - Nightly("nightly-2-00-py3k", [ + Nightly("nightly-3-00-py3.3", [ LINUX64, # on speed-old, uses all cores APPLVLLINUX64, # on speed-old, uses 1 core - ], branch="py3k", hour=2, minute=0), + ], branch="py3.3", hour=3, minute=0), # this one has faithfully run every night even though the latest # change to that branch was in January 2013. Re-enable one day. From noreply at buildbot.pypy.org Tue Sep 22 17:09:28 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 22 Sep 2015 17:09:28 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: half of the llgraph tests pass again, need to push through the rest of the unported stuff and tweaking the thing here and there Message-ID: <20150922150928.1680E1C01DE@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79769:9169c6da92d4 Date: 2015-09-22 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/9169c6da92d4/ Log: half of the llgraph tests pass again, need to push through the rest of the unported stuff and tweaking the thing here and there 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 @@ -861,28 +861,36 @@ def bh_vec_int_signext(self, vx, ext): return [heaptracker.int_signext(_vx, ext) for _vx in vx] - def bh_vec_getarrayitem_raw(self, struct, offset, count, descr): - values = [] - for i in range(count): - val = self.bh_getarrayitem_raw(struct, offset + i, descr) - values.append(val) - return values + def build_getarrayitem(func): + def method(self, struct, offset, descr): + values = [] + count = self.vector_register_size // descr.get_item_size_in_bytes() + assert count > 0 + for i in range(count): + val = func(self, struct, offset + i, descr) + values.append(val) + return values + return method - def bh_vec_getarrayitem_gc(self, struct, offset, count, descr): - values = [] - for i in range(count): - val = self.bh_getarrayitem_gc(struct, offset + i, descr) - values.append(val) - return values + bh_vec_getarrayitem_gc_i = build_getarrayitem(bh_getarrayitem_gc) + bh_vec_getarrayitem_gc_f = build_getarrayitem(bh_getarrayitem_gc) + bh_vec_getarrayitem_raw_i = build_getarrayitem(bh_getarrayitem_raw) + bh_vec_getarrayitem_raw_f = build_getarrayitem(bh_getarrayitem_raw) + del build_getarrayitem - def bh_vec_raw_load(self, struct, offset, count, descr): + def _bh_vec_raw_load(self, struct, offset, descr): values = [] stride = descr.get_item_size_in_bytes() + count = self.vector_register_size // descr.get_item_size_in_bytes() + assert count > 0 for i in range(count): val = self.bh_raw_load(struct, offset + i*stride, descr) values.append(val) return values + bh_vec_raw_load_i = _bh_vec_raw_load + bh_vec_raw_load_f = _bh_vec_raw_load + def bh_vec_raw_store(self, struct, offset, newvalues, descr): stride = descr.get_item_size_in_bytes() for i,n in enumerate(newvalues): @@ -944,7 +952,17 @@ return hash(self) def setenv(self, box, arg): - if box.type == INT: + if box.is_vector(): + if box.datatype == INT: + _type = lltype.Signed + for i,a in enumerate(arg): + if isinstance(a, bool): + arg[i] = int(a) + elif box.datatype == FLOAT: + _type = longlong.FLOATSTORAGE + else: + raise AssertionError(box) + elif box.type == INT: # typecheck the result if isinstance(arg, bool): arg = int(arg) @@ -953,16 +971,6 @@ assert lltype.typeOf(arg) == llmemory.GCREF elif box.type == FLOAT: assert lltype.typeOf(arg) == longlong.FLOATSTORAGE - elif box.type == VECTOR: - if box.item_type == INT: - _type = lltype.Signed - for i,a in enumerate(arg): - if isinstance(a, bool): - arg[i] = int(a) - elif box.item_type == FLOAT: - _type = longlong.FLOATSTORAGE - else: - raise AssertionError(box) else: raise AssertionError(box) # @@ -1013,12 +1021,9 @@ # ----------------------------------------------------- def _accumulate(self, descr, failargs, values): - for i,box in enumerate(self.current_op.getfailargs()): - if box is None: - continue - accum = box.getaccum() - if not accum: - continue + accuminfo = descr.rd_accum_list + while accuminfo: + i = accuminfo.getpos_in_failargs() value = values[i] assert isinstance(value, list) if accum.operator == '+': @@ -1029,6 +1034,7 @@ else: raise NotImplementedError("accum operator in fail guard") values[i] = value + accuminfo = accuminfo.next() def fail_guard(self, descr, saved_data=None): values = [] diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -18,7 +18,6 @@ from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader from rpython.jit.codewriter import heaptracker, longlong - def giveup(): from rpython.jit.metainterp.pyjitpl import SwitchToBlackhole raise SwitchToBlackhole(Counters.ABORT_BRIDGE) @@ -149,7 +148,6 @@ loop = TreeLoop(name_prefix + name) return loop - def make_jitcell_token(jitdriver_sd): jitcell_token = JitCellToken() jitcell_token.outermost_jitdriver_sd = jitdriver_sd @@ -324,55 +322,14 @@ label_token.short_preamble, metainterp.box_names_memo) loop.operations = ([start_label] + preamble_ops + loop_info.extra_same_as + [loop_info.label_op] + loop_ops) - if loop.versions is not None: - # every different loop version must update their target tokens - for version in loop.versions: - version.update_token(jitcell_token, all_target_tokens) if not we_are_translated(): loop.check_consistency() send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop", inputargs, metainterp.box_names_memo) - record_loop_or_bridge(metainterp_sd, loop) - generate_pending_loop_versions(loop, jitdriver_sd, metainterp, jitcell_token) + loop_info.post_loop_compilation(loop, jitdriver_sd, metainterp, jitcell_token) return start_descr -def generate_pending_loop_versions(loop, jitdriver_sd, metainterp, jitcell_token): - """ if a loop version is created for a guard instruction (e.g. they are known - to fail frequently) then a version can be created that is immediatly compiled - and stitched to the guard. - """ - metainterp_sd = metainterp.staticdata - cpu = metainterp_sd.cpu - if loop.versions: - # compile each version once for the first fail descr! - # this assumes that the root trace (= loop) is already compiled - compiled = {} - info = loop.version_info - for descr in info.descrs: - version = info.get(descr) - if not version: - # the guard might have been removed from the trace - continue - if version not in compiled: - assert isinstance(descr, ResumeGuardDescr) - vl = create_empty_loop(metainterp) - vl.inputargs = version.inputargs - vl.operations = version.operations - vl.original_jitcell_token = jitcell_token - asminfo = send_bridge_to_backend(jitdriver_sd, metainterp_sd, - descr, version.inputargs, - version.operations, jitcell_token) - record_loop_or_bridge(metainterp_sd, vl) - assert asminfo is not None - compiled[version] = (asminfo, descr, version, jitcell_token) - else: - param = compiled[version] - cpu.stitch_bridge(descr, param) - - loop.versions = None - loop.version_info = None - def compile_retrace(metainterp, greenkey, start, inputargs, jumpargs, partial_trace, resumekey, start_state): diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -501,7 +501,6 @@ def __init__(self, name): self.name = name - self.versions = [] # self.operations = list of ResOperations # ops of the kind 'guard_xxx' contain a further list of operations, # which may itself contain 'guard_xxx' and so on, making a tree. @@ -520,31 +519,6 @@ insns[opname] = insns.get(opname, 0) + 1 return insns - # XXX VECdef append_loop(self, loop, all_target_tokens): - # XXX VEC # append e.g. the peeled loop to this loop! - # XXX VEC jump = loop.operations[-1] - # XXX VEC assert jump.getdescr() is not None - # XXX VEC target_token = None - # XXX VEC i = 0 - # XXX VEC # adds all target token until the one is found that jumps from the - # XXX VEC # last instruction to the label - # XXX VEC while i < len(loop.operations) and target_token is not jump.getdescr(): - # XXX VEC # there is another label - # XXX VEC op = loop.operations[i] - # XXX VEC if op.getopnum() == rop.LABEL: - # XXX VEC target_token = op.getdescr() - # XXX VEC assert isinstance(target_token, TargetToken) - # XXX VEC all_target_tokens.append(target_token) - # XXX VEC i += 1 - # XXX VEC # - # XXX VEC self.operations = self.operations[:-1] + loop.operations - # XXX VEC self.versions = loop.versions - # XXX VEC loop.versions = None - # XXX VEC self.version_info = loop.version_info - # XXX VEC loop.version_info = None - # XXX VEC if loop.quasi_immutable_deps: - # XXX VEC self.quasi_immutable_deps.update(loop.quasi_immutable_deps) - def get_operations(self): return self.operations diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -246,6 +246,7 @@ self.renamer.start_renaming(op, var) continue self.emit_operation(op) + self.renamer.rename(loop.jump) # loop.operations = self._newoperations[:] 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 @@ -33,6 +33,9 @@ def final(self): return True + def post_loop_compilation(self, loop, jitdriver_sd, metainterp, jitcell_token): + pass + class Optimization(object): next_optimization = None diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -44,21 +44,39 @@ self.jump = jump assert self.jump.getopnum() == rop.JUMP - def operation_list(self): - return [self.label] + self.operations + [self.jump] - - def finaloplist(self): + def finaloplist(self, jitcell_token=None, label=False): oplist = [] + if jitcell_token: + token = TargetToken(jitcell_token) + token.original_jitcell_token = jitcell_token + jitcell_token.target_tokens.append(token) + self.label.setdescr(token) + if self.prefix_label: + token = TargetToken(jitcell_token) + token.original_jitcell_token = jitcell_token + jitcell_token.target_tokens.append(token) + self.prefix_label.setdescr(token) + self.jump.setdescr(token) if self.prefix_label: - oplist = [self.prefix_label] + self.prefix + oplist = self.prefix + [self.prefix_label] elif self.prefix: oplist = self.prefix + if label: + oplist = [self.label] + oplist return oplist + self.operations + [self.jump] - def assemble_oplist(self): - oplist = self.prefix + [self.prefix_label] + \ - loop.operations + [loop.jump] - return oplist + def clone(self): + oplist = [] + renamer = Renamer() + for op in self.operations: + newop = op.copy() + renamer.rename(newop) + if not newop.returns_void(): + renamer.start_renaming(op, newop) + oplist.append(newop) + jump = self.jump.copy() + renamer.rename(jump) + return VectorLoop(self.label.copy(), oplist, jump) def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ @@ -67,38 +85,37 @@ return # the original loop (output of optimize_unroll) info = LoopVersionInfo(loop_info) - version = info.snapshot(loop_ops, info.label_op) loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) + version = info.snapshot(loop) try: debug_start("vec-opt-loop") - metainterp_sd.logger_noopt.log_loop([], loop.operation_list(), -2, None, None, "pre vectorize") + metainterp_sd.logger_noopt.log_loop([], loop.finaloplist(label=True), -2, None, None, "pre vectorize") metainterp_sd.profiler.count(Counters.OPT_VECTORIZE_TRY) # start = time.clock() opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, warmstate.vec_cost) - opt.propagate_all_forward(info, loop) - # - gso = GuardStrengthenOpt(opt.dependency_graph.index_vars, opt.has_two_labels) + index_vars = opt.propagate_all_forward(info, loop) + gso = GuardStrengthenOpt(index_vars) gso.propagate_all_forward(info, loop, user_code) end = time.clock() # metainterp_sd.profiler.count(Counters.OPT_VECTORIZED) - metainterp_sd.logger_noopt.log_loop([], loop.operation_list(), -2, None, None, "post vectorize") - # + metainterp_sd.logger_noopt.log_loop([], loop.finaloplist(label=True), -2, None, None, "post vectorize") nano = int((end-start)*10.0**9) debug_print("# vecopt factor: %d opcount: (%d -> %d) took %dns" % \ - (opt.unroll_count+1, len(version.operations), len(loop.operations), nano)) + (opt.unroll_count+1, len(version.loop.operations), len(loop.operations), nano)) debug_stop("vec-opt-loop") # - return info, loop.assemble_oplist() + info.label_op = loop.label + return info, loop.finaloplist() except NotAVectorizeableLoop: debug_stop("vec-opt-loop") # vectorization is not possible - return loop_info, version.operations + return loop_info, version.loop.finaloplist() except NotAProfitableLoop: debug_stop("vec-opt-loop") # cost model says to skip this loop - return loop_info, version.operations + return loop_info, version.loop.finaloplist() except Exception as e: debug_stop("vec-opt-loop") debug_print("failed to vectorize loop. THIS IS A FATAL ERROR!") @@ -162,10 +179,7 @@ self.packset = None self.unroll_count = 0 self.smallest_type_bytes = 0 - self.sched_data = None - self.appended_arg_count = 0 self.orig_label_args = None - self.has_two_labels = False def propagate_all_forward(self, info, loop): self.orig_label_args = loop.label.getarglist_copy() @@ -198,10 +212,7 @@ self.schedule(state) if not state.profitable(): raise NotAProfitableLoop() - - def emit_unrolled_operation(self, op): - self._last_emitted_op = op - self._newoperations.append(op) + return graph.index_vars def unroll_loop_iterations(self, loop, unroll_count): """ Unroll the loop X times. unroll_count + 1 = unroll_factor """ @@ -264,7 +275,6 @@ value = renamer.rename_box(arg) loop.jump.setarg(i, value) # - #self.emit_unrolled_operation(jump_op) loop.operations = operations + unrolled def linear_find_smallest_type(self, loop): @@ -304,15 +314,12 @@ for node_b,memref_b in memory_refs: if memref_a is memref_b: continue - #print "???", memref_a.index_var, memref_b.index_var # instead of compare every possible combination and # exclue a_opidx == b_opidx only consider the ones # that point forward: if memref_a.is_adjacent_after(memref_b): - print node_a.getindex(), "is after", node_b.getindex() pair = self.packset.can_be_packed(node_a, node_b, None, False) if pair: - print "creating mem pair", pair self.packset.add_pack(pair) def extend_packset(self): @@ -357,13 +364,10 @@ def follow_def_uses(self, pack): assert pack.numops() == 2 - print "lprov", pack.leftmost(node=True).provides_count(), - print "rprov", pack.rightmost(node=True).provides_count() for ldep in pack.leftmost(node=True).provides(): for rdep in pack.rightmost(node=True).provides(): lnode = ldep.to rnode = rdep.to - print "trying", lnode.getindex(), rnode.getindex(), lnode, rnode left = pack.leftmost() args = lnode.getoperation().getarglist() if left is None or left not in args: @@ -372,10 +376,7 @@ if isomorph and lnode.is_before(rnode): pair = self.packset.can_be_packed(lnode, rnode, pack, True) if pair: - print "creating pair" , pair, pair.operations[0].op, pair.operations[1].op self.packset.add_pack(pair) - else: - print "!!!creating pair" , lnode, rnode def combine_packset(self): """ Combination is done iterating the packs that have @@ -439,38 +440,38 @@ return state.post_schedule() - def prepend_invariant_operations(self, sched_data): - """ Add invariant operations to the trace loop. returns the operation list - as first argument and a second a boolean value. - """ - oplist = self._newoperations + #def prepend_invariant_operations(self, sched_data): + # """ Add invariant operations to the trace loop. returns the operation list + # as first argument and a second a boolean value. + # """ + # oplist = self._newoperations - if len(sched_data.invariant_oplist) > 0: - label = oplist[0] - assert label.getopnum() == rop.LABEL - # - jump = oplist[-1] - assert jump.getopnum() == rop.JUMP - # - label_args = label.getarglist()[:] - jump_args = jump.getarglist() - for var in sched_data.invariant_vector_vars: - label_args.append(var) - jump_args.append(var) - # - # in case of any invariant_vector_vars, the label is restored - # and the invariant operations are added between the original label - # and the new label - descr = label.getdescr() - assert isinstance(descr, TargetToken) - token = TargetToken(descr.targeting_jitcell_token) - oplist[0] = label.copy_and_change(label.getopnum(), args=label_args, descr=token) - oplist[-1] = jump.copy_and_change(jump.getopnum(), args=jump_args, descr=token) - # - return [ResOperation(rop.LABEL, self.orig_label_args, None, descr)] + \ - sched_data.invariant_oplist + oplist - # - return oplist + # if len(sched_data.invariant_oplist) > 0: + # label = oplist[0] + # assert label.getopnum() == rop.LABEL + # # + # jump = oplist[-1] + # assert jump.getopnum() == rop.JUMP + # # + # label_args = label.getarglist()[:] + # jump_args = jump.getarglist() + # for var in sched_data.invariant_vector_vars: + # label_args.append(var) + # jump_args.append(var) + # # + # # in case of any invariant_vector_vars, the label is restored + # # and the invariant operations are added between the original label + # # and the new label + # descr = label.getdescr() + # assert isinstance(descr, TargetToken) + # token = TargetToken(descr.targeting_jitcell_token) + # oplist[0] = label.copy_and_change(label.getopnum(), args=label_args, descr=token) + # oplist[-1] = jump.copy_and_change(jump.getopnum(), args=jump_args, descr=token) + # # + # return [ResOperation(rop.LABEL, self.orig_label_args, None, descr)] + \ + # sched_data.invariant_oplist + oplist + # # + # return oplist def analyse_index_calculations(self, loop): """ Tries to move guarding instructions an all the instructions that @@ -586,7 +587,6 @@ cost, benefit_factor = self.cb_signext(pack) # self.savings += benefit_factor * times - cost - print "$$$ recording", benefit_factor, "*", times, "-", cost, "now:", self.savings def cb_signext(self, pack): left = pack.leftmost() @@ -606,10 +606,8 @@ if src.datatype == FLOAT: if index == 1 and count == 1: self.savings -= 2 - print "$$$ vector pack -2 now:", self.savings return self.savings -= count - print "$$$ vector pack ", count, "now", self.savings def record_vector_unpack(self, src, index, count): self.record_vector_pack(src, index, count) @@ -799,16 +797,13 @@ for i,pack in enumerate(self.packs): load = pack.pack_load(self.vec_reg_size) if load > Pack.FULL: - print "overloaded pack", pack pack.split(newpacks, self.vec_reg_size) continue if load < Pack.FULL: - print "underloaded pack", pack for op in pack.operations: op.priority = -100 pack.clear() self.packs[i] = None continue - print "fully packed", pack self.packs = [pack for pack in self.packs + newpacks if pack] diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -1,6 +1,9 @@ from rpython.jit.metainterp.resoperation import rop from rpython.jit.metainterp.optimizeopt.optimizer import BasicLoopInfo +from rpython.jit.metainterp.compile import (send_bridge_to_backend, record_loop_or_bridge, + ResumeGuardDescr, create_empty_loop) + class LoopVersionInfo(BasicLoopInfo): def __init__(self, info): @@ -40,21 +43,47 @@ return self.leads_to.get(descr, None) def snapshot(self, loop): - operations = loop.finaloplist() - label = loop.label - oplist = [] - ignore = (rop.DEBUG_MERGE_POINT,) - for op in operations: - if op.getopnum() in ignore: - continue - cloned = op.copy_and_change(op.getopnum()) - oplist.append(cloned) - version = LoopVersion(oplist, label) + newloop = loop.clone() + version = LoopVersion(newloop) version.setup_once(self) self.versions.append(version) # register the faildescr for later stitching return version + def post_loop_compilation(self, loop, jitdriver_sd, metainterp, jitcell_token): + """ if a loop version is created for a guard instruction (e.g. they are known + to fail frequently) then a version can be created that is immediatly compiled + and stitched to the guard. + """ + metainterp_sd = metainterp.staticdata + cpu = metainterp_sd.cpu + if not self.versions: + return + # compile each version once for the first fail descr! + # this assumes that the root trace (= loop) is already compiled + compiled = {} + for descr in self.descrs: + version = self.get(descr) + if not version: + # the guard might have been removed from the trace + continue + if version not in compiled: + assert isinstance(descr, ResumeGuardDescr) + vl = version.create_backend_loop(metainterp, jitcell_token) + asminfo = send_bridge_to_backend(jitdriver_sd, metainterp_sd, + descr, vl.inputargs, + vl.operations, jitcell_token, + metainterp.box_names_memo) + record_loop_or_bridge(metainterp_sd, vl) + assert asminfo is not None + compiled[version] = (asminfo, descr, version, jitcell_token) + else: + param = compiled[version] + cpu.stitch_bridge(descr, param) + + self.versions = None # dismiss versions + + class LoopVersion(object): """ A special version of a trace loop. Use loop.snaphost() to create one instance and attach it to a guard descr. @@ -62,26 +91,26 @@ """ _attrs_ = ('label', 'operations', 'inputargs', 'renamed_inputargs') - def __init__(self, operations, label): - self.label = label - self.operations = operations - self.inputargs = label.getarglist() - self.renamed_inputargs = label.getarglist() + def __init__(self, loop): + self.loop = loop + self.inputargs = loop.label.getarglist() + self.renamed_inputargs = loop.label.getarglist() def setup_once(self, info): - for op in self.operations: - if op.is_guard(): - olddescr = op.getdescr() - if not olddescr: - continue - descr = olddescr.clone() - op.setdescr(descr) - if descr.loop_version(): - toversion = info.leads_to.get(olddescr,None) - if toversion: - info.track(op, descr, toversion) - else: - assert 0, "olddescr must be found" + for op in self.loop.operations: + if not op.is_guard(): + continue + olddescr = op.getdescr() + if not olddescr: + continue + descr = olddescr.clone() + op.setdescr(descr) + if descr.loop_version(): + toversion = info.leads_to.get(olddescr,None) + if toversion: + info.track(op, descr, toversion) + else: + assert 0, "olddescr must be found" def update_token(self, jitcell_token, all_target_tokens): # this is only invoked for versioned loops! @@ -111,6 +140,13 @@ label.setdescr(token) jump.setdescr(token) + def create_backend_loop(self, metainterp, jitcell_token): + vl = create_empty_loop(metainterp) + vl.operations = self.loop.finaloplist(jitcell_token,True) + vl.inputargs = self.loop.label.getarglist_copy() + vl.original_jitcell_token = jitcell_token + return vl + #def index_of_first(opnum, operations, pass_by=0): # """ returns the position of the first operation matching the opnum. diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -27,8 +27,11 @@ class AbstractValue(object): _repr_memo = CountingDict() is_info_class = False - _attrs_ = () namespace = None + _attrs_ = ('datatype', 'bytesize', 'signed') + datatype = '\x00' + bytesize = -1 # -1 means the biggest size known to the machine + signed = True def _get_hash_(self): return compute_identity_hash(self) @@ -110,11 +113,6 @@ class Typed(object): _mixin_ = True - _attrs_ = ('datatype', 'bytesize', 'signed') - - datatype = '\x00' - bytesize = -1 # -1 means the biggest size known to the machine - signed = True def inittype(self): if self.returns_void(): @@ -124,6 +122,9 @@ if self.is_primitive_array_access(): descr = self.getdescr() + if not we_are_translated(): + from rpython.jit.backend.llgraph.runner import _getdescr + descr = _getdescr(self) type = self.type if descr.is_array_of_floats() or descr.concrete_type == 'f': type = 'f' @@ -131,8 +132,10 @@ self.sign = descr.is_item_signed() self.datatype = type elif self.opnum == rop.INT_SIGNEXT: + from rpython.jit.metainterp import history arg0 = self.getarg(0) arg1 = self.getarg(1) + assert isinstance(arg1, history.ConstInt) signed = True if not arg0.is_constant(): signed = arg0.signed @@ -182,6 +185,7 @@ _attrs_ = ('_forwarded',) _forwarded = None # either another resop or OptInfo + def get_forwarded(self): return self._forwarded @@ -435,6 +439,9 @@ primitive type (int,float) """ if self.is_primitive_load() or self.is_primitive_store(): descr = self.getdescr() + if not we_are_translated(): + from rpython.jit.backend.llgraph.runner import _getdescr + descr = _getdescr(self) if descr and descr.is_array_of_primitives(): return True return False diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -57,6 +57,12 @@ self.scalar_box = box self.vector_loc = loc + def getpos_in_failargs(self): + return self.scalar_position + + def next(self): + return self.prev + def __repr__(self): return 'AccumInfo(%s,%s,%s,%s,%s)' % (self.prev is None, self.accum_operation, diff --git a/rpython/jit/metainterp/test/test_vector.py b/rpython/jit/metainterp/test/test_vector.py --- a/rpython/jit/metainterp/test/test_vector.py +++ b/rpython/jit/metainterp/test/test_vector.py @@ -65,7 +65,7 @@ res = self.meta_interp(f, [i]) assert res == f(i) - @py.test.mark.parametrize('i',[1,2,3,8,17,128,130,500,501,502,1300]) + @py.test.mark.parametrize('i',[1,2,3,8,17,128,130,131,142,143]) def test_vectorize_array_get_set(self,i): myjitdriver = JitDriver(greens = [], reds = 'auto', From noreply at buildbot.pypy.org Tue Sep 22 17:10:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 17:10:24 +0200 (CEST) Subject: [pypy-commit] pypy default: Move this delicate logic of choosing whether to save exception, whether Message-ID: <20150922151024.77CE81C01DE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79770:75bdab748aac Date: 2015-09-22 17:00 +0200 http://bitbucket.org/pypy/pypy/changeset/75bdab748aac/ Log: Move this delicate logic of choosing whether to save exception, whether it's a guard_not_forced, etc. to llsupport instead of in the backends diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -909,7 +909,7 @@ descr.adr_jump_offset = failure_recovery_pos relative_offset = tok.pos_recovery_stub - tok.offset guard_pos = block_start + tok.offset - if not tok.is_guard_not_invalidated: + if not tok.guard_not_invalidated(): # patch the guard jump to the stub # overwrite the generate NOP with a B_offs to the pos of the # stub diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -36,11 +36,9 @@ class ArmGuardToken(GuardToken): def __init__(self, cpu, gcmap, faildescr, failargs, fail_locs, - offset, exc, frame_depth, is_guard_not_invalidated=False, - is_guard_not_forced=False, fcond=c.AL): + offset, guard_opnum, frame_depth, fcond=c.AL): GuardToken.__init__(self, cpu, gcmap, faildescr, failargs, fail_locs, - exc, frame_depth, is_guard_not_invalidated, - is_guard_not_forced) + guard_opnum, frame_depth) self.fcond = fcond self.offset = offset @@ -175,10 +173,7 @@ self.mc.RSB_ri(resloc.value, l0.value, imm=0) return fcond - def build_guard_token(self, op, frame_depth, arglocs, offset, fcond, save_exc, - is_guard_not_invalidated=False, - is_guard_not_forced=False): - assert isinstance(save_exc, bool) + def build_guard_token(self, op, frame_depth, arglocs, offset, fcond): assert isinstance(fcond, int) descr = op.getdescr() assert isinstance(descr, AbstractFailDescr) @@ -189,16 +184,12 @@ failargs=op.getfailargs(), fail_locs=arglocs, offset=offset, - exc=save_exc, + guard_opnum=op.getopnum(), frame_depth=frame_depth, - is_guard_not_invalidated=is_guard_not_invalidated, - is_guard_not_forced=is_guard_not_forced, fcond=fcond) return token - def _emit_guard(self, op, arglocs, save_exc, - is_guard_not_invalidated=False, - is_guard_not_forced=False): + def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False): if is_guard_not_invalidated: fcond = c.cond_none else: @@ -206,10 +197,9 @@ self.guard_success_cc = c.cond_none assert fcond != c.cond_none pos = self.mc.currpos() - token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond, save_exc, - is_guard_not_invalidated, - is_guard_not_forced) + token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond) self.pending_guards.append(token) + assert token.guard_not_invalidated() == is_guard_not_invalidated # For all guards that are not GUARD_NOT_INVALIDATED we emit a # breakpoint to ensure the location is patched correctly. In the case # of GUARD_NOT_INVALIDATED we use just a NOP, because it is only @@ -221,12 +211,12 @@ return c.AL def emit_op_guard_true(self, op, arglocs, regalloc, fcond): - fcond = self._emit_guard(op, arglocs, save_exc=False) + fcond = self._emit_guard(op, arglocs) return fcond def emit_op_guard_false(self, op, arglocs, regalloc, fcond): self.guard_success_cc = c.get_opposite_of(self.guard_success_cc) - fcond = self._emit_guard(op, arglocs, save_exc=False) + fcond = self._emit_guard(op, arglocs) return fcond def emit_op_guard_value(self, op, arglocs, regalloc, fcond): @@ -244,7 +234,7 @@ self.mc.VCMP(l0.value, l1.value) self.mc.VMRS(cond=fcond) self.guard_success_cc = c.EQ - fcond = self._emit_guard(op, failargs, save_exc=False) + fcond = self._emit_guard(op, failargs) return fcond emit_op_guard_nonnull = emit_op_guard_true @@ -256,14 +246,14 @@ def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): @@ -288,7 +278,7 @@ def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): @@ -309,7 +299,7 @@ self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value) self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff)) self.guard_success_cc = c.NE - self._emit_guard(op, arglocs[1:], save_exc=False) + self._emit_guard(op, arglocs[1:]) return fcond def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): @@ -353,12 +343,11 @@ self.mc.CMP_rr(r.ip.value, r.lr.value) # the guard passes if we get a result of "below or equal" self.guard_success_cc = c.LS - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - return self._emit_guard(op, locs, save_exc=False, - is_guard_not_invalidated=True) + return self._emit_guard(op, locs, is_guard_not_invalidated=True) def emit_op_label(self, op, arglocs, regalloc, fcond): self._check_frame_depth_debug(self.mc) @@ -498,7 +487,7 @@ self.mc.LDR_ri(loc.value, loc.value) self.mc.CMP_ri(loc.value, 0) self.guard_success_cc = c.EQ - fcond = self._emit_guard(op, failargs, save_exc=True) + fcond = self._emit_guard(op, failargs) # If the previous operation was a COND_CALL, overwrite its conditional # jump to jump over this GUARD_NO_EXCEPTION as well, if we can if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: @@ -515,7 +504,7 @@ self.mc.CMP_rr(r.ip.value, loc.value) self.guard_success_cc = c.EQ - self._emit_guard(op, failargs, save_exc=True) + self._emit_guard(op, failargs) self._store_and_reset_exception(self.mc, resloc) return fcond @@ -1047,7 +1036,8 @@ def store_force_descr(self, op, fail_locs, frame_depth): pos = self.mc.currpos() - guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, c.AL, True, False, True) + guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, c.AL) + assert guard_token.must_save_exception() #self.pending_guards.append(guard_token) self._finish_gcmap = guard_token.gcmap self._store_force_index(op) @@ -1152,7 +1142,7 @@ self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) + self._emit_guard(op, arglocs) return fcond def _genop_call_may_force(self, op, arglocs, regalloc, fcond): diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -23,8 +23,8 @@ class GuardToken(object): - def __init__(self, cpu, gcmap, faildescr, failargs, fail_locs, exc, - frame_depth, is_guard_not_invalidated, is_guard_not_forced): + def __init__(self, cpu, gcmap, faildescr, failargs, fail_locs, + guard_opnum, frame_depth): assert isinstance(faildescr, AbstractFailDescr) self.cpu = cpu self.faildescr = faildescr @@ -32,9 +32,16 @@ self.fail_locs = fail_locs self.gcmap = self.compute_gcmap(gcmap, failargs, fail_locs, frame_depth) - self.exc = exc - self.is_guard_not_invalidated = is_guard_not_invalidated - self.is_guard_not_forced = is_guard_not_forced + self.guard_opnum = guard_opnum + + def guard_not_invalidated(self): + return self.guard_opnum == rop.GUARD_NOT_INVALIDATED + + def must_save_exception(self): + guard_opnum = self.guard_opnum + return (guard_opnum == rop.GUARD_EXCEPTION or + guard_opnum == rop.GUARD_NO_EXCEPTION or + guard_opnum == rop.GUARD_NOT_FORCED) def compute_gcmap(self, gcmap, failargs, fail_locs, frame_depth): # note that regalloc has a very similar compute, but @@ -172,7 +179,7 @@ if box is not None and box.type == FLOAT: withfloats = True break - exc = guardtok.exc + exc = guardtok.must_save_exception() target = self.failure_recovery_code[exc + 2 * withfloats] fail_descr = cast_instance_to_gcref(guardtok.faildescr) fail_descr = rffi.cast(lltype.Signed, fail_descr) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -590,7 +590,7 @@ relative_target = tok.pos_recovery_stub - (tok.pos_jump_offset + 4) assert rx86.fits_in_32bits(relative_target) # - if not tok.is_guard_not_invalidated: + if not tok.guard_not_invalidated(): mc = codebuf.MachineCodeBlockWrapper() mc.writeimm32(relative_target) mc.copy_to_raw_memory(addr) @@ -1762,15 +1762,9 @@ def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): - exc = (guard_opnum == rop.GUARD_EXCEPTION or - guard_opnum == rop.GUARD_NO_EXCEPTION or - guard_opnum == rop.GUARD_NOT_FORCED) - is_guard_not_invalidated = guard_opnum == rop.GUARD_NOT_INVALIDATED - is_guard_not_forced = guard_opnum == rop.GUARD_NOT_FORCED gcmap = allocate_gcmap(self, frame_depth, JITFRAME_FIXED_SIZE) - return GuardToken(self.cpu, gcmap, faildescr, failargs, - fail_locs, exc, frame_depth, - is_guard_not_invalidated, is_guard_not_forced) + return GuardToken(self.cpu, gcmap, faildescr, failargs, fail_locs, + guard_opnum, frame_depth) def generate_propagate_error_64(self): assert WORD == 8 From noreply at buildbot.pypy.org Tue Sep 22 17:10:26 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 17:10:26 +0200 (CEST) Subject: [pypy-commit] pypy default: oups Message-ID: <20150922151026.AAB111C01DE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79771:8b1143d9fb7f Date: 2015-09-22 17:08 +0200 http://bitbucket.org/pypy/pypy/changeset/8b1143d9fb7f/ Log: oups diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1037,7 +1037,6 @@ def store_force_descr(self, op, fail_locs, frame_depth): pos = self.mc.currpos() guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, c.AL) - assert guard_token.must_save_exception() #self.pending_guards.append(guard_token) self._finish_gcmap = guard_token.gcmap self._store_force_index(op) From noreply at buildbot.pypy.org Tue Sep 22 17:32:30 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 17:32:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Typo Message-ID: <20150922153230.F23EE1C01DE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79772:a15fd26dbd48 Date: 2015-09-22 17:31 +0200 http://bitbucket.org/pypy/pypy/changeset/a15fd26dbd48/ Log: Typo diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -181,7 +181,7 @@ kwds.setdefault('supports_singlefloats', True) self._run([types.float] * 2, types.double, [r_singlefloat(10.5), r_singlefloat(31.5)], - -4.5) + -4.5, **kwds) def test_simple_call_singlefloat(self, **kwds): kwds.setdefault('supports_singlefloats', True) From noreply at buildbot.pypy.org Tue Sep 22 17:50:41 2015 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 22 Sep 2015 17:50:41 +0200 (CEST) Subject: [pypy-commit] pypy detect_egd2: Test has() more thoroughly. Message-ID: <20150922155041.CEB591C043B@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: detect_egd2 Changeset: r79773:9be551cbb656 Date: 2015-09-22 16:50 +0100 http://bitbucket.org/pypy/pypy/changeset/9be551cbb656/ Log: Test has() more thoroughly. diff --git a/rpython/rtyper/tool/test/test_rffi_platform.py b/rpython/rtyper/tool/test/test_rffi_platform.py --- a/rpython/rtyper/tool/test/test_rffi_platform.py +++ b/rpython/rtyper/tool/test/test_rffi_platform.py @@ -270,12 +270,34 @@ [("d_name", lltype.FixedSizeArray(rffi.CHAR, 1))]) assert dirent.c_d_name.length == 32 -def test_has(): +def test_has_0001(): assert rffi_platform.has("x", "int x = 3;") assert not rffi_platform.has("x", "") # has() should also not crash if it is given an invalid #include assert not rffi_platform.has("x", "#include ") +def test_has_0002(): + assert rffi_platform.has("pow", "#include ", libraries=["m"]) + +def test_has_0003(): + """multiple libraries""" + assert rffi_platform.has("pow", "#include ", libraries=["m", "c"]) + +def test_has_0004(): + """bogus symbol name""" + assert not rffi_platform.has("pow", "#include ", + libraries=["boguslibname"]) + +def test_has_0005(): + """bogus symbol name and lib name""" + assert not rffi_platform.has("bogus_symbol_name", "#include ", + libraries=["boguslibname"]) + +def test_has_0006(): + """missing include""" + assert not rffi_platform.has("pow", "", libraries=["m"]) + + def test_verify_eci(): eci = ExternalCompilationInfo() rffi_platform.verify_eci(eci) From noreply at buildbot.pypy.org Tue Sep 22 17:54:59 2015 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 22 Sep 2015 17:54:59 +0200 (CEST) Subject: [pypy-commit] pypy detect_egd2: Close branch detect_egd2 Message-ID: <20150922155459.A137D1C043B@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: detect_egd2 Changeset: r79774:593782a9b15f Date: 2015-09-22 16:55 +0100 http://bitbucket.org/pypy/pypy/changeset/593782a9b15f/ Log: Close branch detect_egd2 From noreply at buildbot.pypy.org Tue Sep 22 17:55:16 2015 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 22 Sep 2015 17:55:16 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged in detect_egd2 (pull request #333) Message-ID: <20150922155516.39C2F1C043B@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: Changeset: r79775:7a75425fd561 Date: 2015-09-22 16:55 +0100 http://bitbucket.org/pypy/pypy/changeset/7a75425fd561/ Log: Merged in detect_egd2 (pull request #333) Deal with platforms without RAND_egd(). diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -241,20 +241,26 @@ res = libssl_RAND_status() return space.wrap(res) - @unwrap_spec(path=str) - def RAND_egd(space, path): - """RAND_egd(path) -> bytes + if HAVE_OPENSSL_RAND_EGD: + @unwrap_spec(path=str) + def RAND_egd(space, path): + """RAND_egd(path) -> bytes - Queries the entropy gather daemon (EGD) on socket path. Returns number - of bytes read. Raises socket.sslerror if connection to EGD fails or - if it does provide enough data to seed PRNG.""" - with rffi.scoped_str2charp(path) as socket_path: - bytes = libssl_RAND_egd(socket_path) - if bytes == -1: - raise ssl_error(space, - "EGD connection failed or EGD did not return " - "enough data to seed the PRNG") - return space.wrap(bytes) + Queries the entropy gather daemon (EGD) on socket path. Returns number + of bytes read. Raises socket.sslerror if connection to EGD fails or + if it does provide enough data to seed PRNG.""" + with rffi.scoped_str2charp(path) as socket_path: + bytes = libssl_RAND_egd(socket_path) + if bytes == -1: + raise ssl_error(space, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG") + return space.wrap(bytes) + else: + # Dummy func for platforms missing RAND_egd(). Most likely LibreSSL. + @unwrap_spec(path=str) + def RAND_egd(space, path): + raise ssl_error(space, "RAND_egd unavailable") class _SSLSocket(W_Root): diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -36,7 +36,8 @@ assert isinstance(_ssl.OPENSSL_VERSION_INFO, tuple) assert len(_ssl.OPENSSL_VERSION_INFO) == 5 assert isinstance(_ssl.OPENSSL_VERSION, str) - assert 'openssl' in _ssl.OPENSSL_VERSION.lower() + lower_version = _ssl.OPENSSL_VERSION.lower() + assert 'openssl' in lower_version or "libressl" in lower_version assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int) @@ -69,8 +70,9 @@ def test_sslwrap(self): import _ssl, _socket, sys, gc - if sys.platform == 'darwin' or 'freebsd' in sys.platform: - skip("hangs indefinitely on OSX & FreeBSD (also on CPython)") + if sys.platform == 'darwin' or 'freebsd' in sys.platform or \ + 'openbsd' in sys.platform: + skip("hangs indefinitely on OSX & BSD (also on CPython)") s = _socket.socket() if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -264,6 +264,9 @@ OPENSSL_NO_ECDH = True HAS_ALPN = OPENSSL_VERSION_NUMBER >= 0x1000200fL and not OPENSSL_NO_TLSEXT +HAVE_OPENSSL_RAND_EGD = rffi_platform.has('RAND_egd("/")', + '#include ', + libraries=['ssl', 'crypto']) def external(name, argtypes, restype, **kw): kw['compilation_info'] = eci @@ -288,7 +291,8 @@ if HAVE_OPENSSL_RAND: ssl_external('RAND_add', [rffi.CCHARP, rffi.INT, rffi.DOUBLE], lltype.Void) ssl_external('RAND_status', [], rffi.INT) - ssl_external('RAND_egd', [rffi.CCHARP], rffi.INT) + if HAVE_OPENSSL_RAND_EGD: + ssl_external('RAND_egd', [rffi.CCHARP], rffi.INT) ssl_external('SSL_CTX_new', [SSL_METHOD], SSL_CTX) ssl_external('SSL_get_SSL_CTX', [SSL], SSL_CTX) ssl_external('SSL_set_SSL_CTX', [SSL, SSL_CTX], SSL_CTX) diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -17,12 +17,15 @@ # # Helpers for simple cases -def eci_from_header(c_header_source, include_dirs=None): +def eci_from_header(c_header_source, include_dirs=None, libraries=None): if include_dirs is None: include_dirs = [] + if libraries is None: + libraries = [] return ExternalCompilationInfo( post_include_bits=[c_header_source], - include_dirs=include_dirs + include_dirs=include_dirs, + libraries=libraries, ) def getstruct(name, c_header_source, interesting_fields): @@ -75,9 +78,10 @@ CConfig._compilation_info_.includes = includes return configure(CConfig)['RESULT'] -def has(name, c_header_source, include_dirs=None): +def has(name, c_header_source, include_dirs=None, libraries=None): class CConfig: - _compilation_info_ = eci_from_header(c_header_source, include_dirs) + _compilation_info_ = \ + eci_from_header(c_header_source, include_dirs, libraries) HAS = Has(name) return configure(CConfig)['HAS'] diff --git a/rpython/rtyper/tool/test/test_rffi_platform.py b/rpython/rtyper/tool/test/test_rffi_platform.py --- a/rpython/rtyper/tool/test/test_rffi_platform.py +++ b/rpython/rtyper/tool/test/test_rffi_platform.py @@ -270,12 +270,34 @@ [("d_name", lltype.FixedSizeArray(rffi.CHAR, 1))]) assert dirent.c_d_name.length == 32 -def test_has(): +def test_has_0001(): assert rffi_platform.has("x", "int x = 3;") assert not rffi_platform.has("x", "") # has() should also not crash if it is given an invalid #include assert not rffi_platform.has("x", "#include ") +def test_has_0002(): + assert rffi_platform.has("pow", "#include ", libraries=["m"]) + +def test_has_0003(): + """multiple libraries""" + assert rffi_platform.has("pow", "#include ", libraries=["m", "c"]) + +def test_has_0004(): + """bogus symbol name""" + assert not rffi_platform.has("pow", "#include ", + libraries=["boguslibname"]) + +def test_has_0005(): + """bogus symbol name and lib name""" + assert not rffi_platform.has("bogus_symbol_name", "#include ", + libraries=["boguslibname"]) + +def test_has_0006(): + """missing include""" + assert not rffi_platform.has("pow", "", libraries=["m"]) + + def test_verify_eci(): eci = ExternalCompilationInfo() rffi_platform.verify_eci(eci) From noreply at buildbot.pypy.org Tue Sep 22 18:05:29 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 18:05:29 +0200 (CEST) Subject: [pypy-commit] pypy default: big-endian fix in the test Message-ID: <20150922160529.4BC321C0557@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79776:02ef361e2443 Date: 2015-09-22 17:55 +0200 http://bitbucket.org/pypy/pypy/changeset/02ef361e2443/ Log: big-endian fix in the test diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -70,6 +70,7 @@ cif_description.exchange_result = (len(avalues)+1) * 16 unroll_avalues = unrolling_iterable(avalues) + BIG_ENDIAN = (sys.byteorder == 'big') def fake_call_impl_any(cif_description, func_addr, exchange_buffer): ofs = 16 @@ -86,13 +87,19 @@ avalue = intmask(avalue) assert got == avalue ofs += 16 + write_to_ofs = 0 if rvalue is not None: write_rvalue = rvalue + if BIG_ENDIAN: + if (lltype.typeOf(write_rvalue) is rffi.SIGNEDCHAR or + lltype.typeOf(write_rvalue) is rffi.UCHAR): + # 'write_rvalue' is an int type smaller than Signed + write_to_ofs = rffi.sizeof(rffi.LONG) - 1 else: write_rvalue = 12923 # ignored TYPE = rffi.CArray(lltype.typeOf(write_rvalue)) data = rffi.ptradd(exchange_buffer, ofs) - rffi.cast(lltype.Ptr(TYPE), data)[0] = write_rvalue + rffi.cast(lltype.Ptr(TYPE), data)[write_to_ofs] = write_rvalue def f(i): exbuf = lltype.malloc(rffi.CCHARP.TO, (len(avalues)+2) * 16, From noreply at buildbot.pypy.org Tue Sep 22 18:23:41 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Tue, 22 Sep 2015 18:23:41 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Add @jit.dont_look_inside to some wrappers Message-ID: <20150922162341.3C9391C0557@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: py3.3 Changeset: r79777:92feef568c35 Date: 2015-09-22 17:23 +0100 http://bitbucket.org/pypy/pypy/changeset/92feef568c35/ Log: Add @jit.dont_look_inside to some wrappers These functions are actually macros on Linux which trips up code generation for the JIT. diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -1659,19 +1659,23 @@ finally: lltype.free(l_utsbuf, flavor='raw') +# These are actually macros on some/most systems c_makedev = external('makedev', [rffi.INT, rffi.INT], rffi.INT) c_major = external('major', [rffi.INT], rffi.INT) c_minor = external('minor', [rffi.INT], rffi.INT) @replace_os_function('makedev') + at jit.dont_look_inside def makedev(maj, min): return c_makedev(maj, min) @replace_os_function('major') + at jit.dont_look_inside def major(dev): return c_major(dev) @replace_os_function('minor') + at jit.dont_look_inside def minor(dev): return c_minor(dev) From noreply at buildbot.pypy.org Tue Sep 22 22:21:57 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 22:21:57 +0200 (CEST) Subject: [pypy-commit] pypy default: This kind of lltype.GcStruct, with many pointer fields to a similar type, Message-ID: <20150922202157.335881C05CE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79778:5925e55c154c Date: 2015-09-22 22:22 +0200 http://bitbucket.org/pypy/pypy/changeset/5925e55c154c/ Log: This kind of lltype.GcStruct, with many pointer fields to a similar type, could lead to a very deep stack causing stack overflows. Fix. 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 @@ -75,15 +75,16 @@ except KeyError: size = symbolic.get_size(STRUCT, gccache.translate_support_code) immutable_flag = heaptracker.is_immutable_struct(STRUCT) - gc_fielddescrs = heaptracker.gc_fielddescrs(gccache, STRUCT) if vtable: assert heaptracker.has_gcstruct_a_vtable(STRUCT) else: assert not heaptracker.has_gcstruct_a_vtable(STRUCT) - sizedescr = SizeDescr(size, gc_fielddescrs, vtable=vtable, + sizedescr = SizeDescr(size, vtable=vtable, immutable_flag=immutable_flag) gccache.init_size_descr(STRUCT, sizedescr) cache[STRUCT] = sizedescr + gc_fielddescrs = heaptracker.gc_fielddescrs(gccache, STRUCT) + sizedescr.gc_fielddescrs = gc_fielddescrs all_fielddescrs = heaptracker.all_fielddescrs(gccache, STRUCT) sizedescr.all_fielddescrs = all_fielddescrs return sizedescr 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 @@ -460,3 +460,12 @@ descr = FieldDescr('descr', 0, 1, FLAG_SIGNED) assert descr.get_integer_min() == -128 assert descr.get_integer_max() == 127 + + +def test_size_descr_stack_overflow_bug(): + c0 = GcCache(False) + S = lltype.GcForwardReference() + P = lltype.Ptr(S) + fields = [('x%d' % i, P) for i in range(1500)] + S.become(lltype.GcStruct('S', *fields)) + get_size_descr(c0, S) From noreply at buildbot.pypy.org Tue Sep 22 22:41:27 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 22 Sep 2015 22:41:27 +0200 (CEST) Subject: [pypy-commit] pypy default: add a question Message-ID: <20150922204127.536CE1C01DE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79779:c17cdaf706dd Date: 2015-09-22 22:41 +0200 http://bitbucket.org/pypy/pypy/changeset/c17cdaf706dd/ Log: add a question 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 @@ -83,6 +83,8 @@ immutable_flag=immutable_flag) gccache.init_size_descr(STRUCT, sizedescr) cache[STRUCT] = sizedescr + # XXX do we really need gc_fielddescrs if we also have + # all_fielddescrs and can ask is_pointer_field() on them? gc_fielddescrs = heaptracker.gc_fielddescrs(gccache, STRUCT) sizedescr.gc_fielddescrs = gc_fielddescrs all_fielddescrs = heaptracker.all_fielddescrs(gccache, STRUCT) From noreply at buildbot.pypy.org Wed Sep 23 07:34:03 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 07:34:03 +0200 (CEST) Subject: [pypy-commit] pypy default: try to fix (or skip) tests Message-ID: <20150923053403.094541C12D4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79780:7ff5c27cb5ad Date: 2015-09-23 07:34 +0200 http://bitbucket.org/pypy/pypy/changeset/7ff5c27cb5ad/ Log: try to fix (or skip) tests diff --git a/rpython/jit/backend/arm/test/test_calling_convention.py b/rpython/jit/backend/arm/test/test_calling_convention.py --- a/rpython/jit/backend/arm/test/test_calling_convention.py +++ b/rpython/jit/backend/arm/test/test_calling_convention.py @@ -10,18 +10,14 @@ from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.test.support import skip_unless_run_slow_tests from rpython.jit.backend.arm.test.test_runner import boxfloat, constfloat -from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.history import (AbstractFailDescr, - AbstractDescr, - BasicFailDescr, - BasicFinalDescr, - BoxInt, Box, BoxPtr, - JitCellToken, TargetToken, - ConstInt, ConstPtr, - BoxFloat, ConstFloat) +from rpython.jit.metainterp.resoperation import rop, InputArgInt, InputArgFloat +from rpython.jit.metainterp.history import JitCellToken skip_unless_run_slow_tests() +boxint = InputArgInt +boxfloat = InputArgFloat.fromfloat + class TestARMCallingConvention(CallingConvTests): # ../../test/calling_convention_test.py @@ -82,9 +78,9 @@ EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([boxfloat(.1) for i in range(7)] + - [BoxInt(1), boxfloat(.2), BoxInt(2), boxfloat(.3), + [boxint(1), boxfloat(.2), boxint(2), boxfloat(.3), boxfloat(.4)]) - res = self.execute_operation(rop.CALL, + res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) for i,j in enumerate(callargs[0]): @@ -112,7 +108,7 @@ EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([boxfloat(.1) for i in range(10)]) - res = self.execute_operation(rop.CALL, + res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) for i,j in enumerate(callargs[0]): @@ -134,8 +130,8 @@ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) - args = ([BoxInt(1) for i in range(10)]) - res = self.execute_operation(rop.CALL, + args = ([boxint(1) for i in range(10)]) + res = self.execute_operation(rop.CALL_I, [funcbox] + args, 'int', descr=calldescr) for i,j in enumerate(callargs[0]): diff --git a/rpython/jit/backend/arm/test/test_generated.py b/rpython/jit/backend/arm/test/test_generated.py --- a/rpython/jit/backend/arm/test/test_generated.py +++ b/rpython/jit/backend/arm/test/test_generated.py @@ -1,4 +1,6 @@ import py +py.test.skip("XXX FIX ME OR KILL ME") + from rpython.jit.metainterp.history import (AbstractFailDescr, AbstractDescr, BasicFailDescr, diff --git a/rpython/jit/backend/arm/test/test_trace_operations.py b/rpython/jit/backend/arm/test/test_trace_operations.py --- a/rpython/jit/backend/arm/test/test_trace_operations.py +++ b/rpython/jit/backend/arm/test/test_trace_operations.py @@ -36,7 +36,7 @@ self.struct_ptr.int1049 = 666 ops = ''' [p0] - i0 = getfield_gc(p0, descr=fielddescr) + i0 = getfield_gc_i(p0, descr=fielddescr) finish(i0) ''' self.interpret(ops, [self.struct_ptr]) From noreply at buildbot.pypy.org Wed Sep 23 09:50:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 09:50:48 +0200 (CEST) Subject: [pypy-commit] cffi default: Issue #221: forbid values from enums with "..." from being accessed Message-ID: <20150923075048.3D39B1C1325@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2272:a6d472e27fab Date: 2015-09-23 09:51 +0200 http://bitbucket.org/cffi/cffi/changeset/a6d472e27fab/ Log: Issue #221: forbid values from enums with "..." from being accessed in ABI mode. diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -634,6 +634,7 @@ for key, tp in ffi._parser._declarations.items(): if not isinstance(tp, model.EnumType): continue + tp.check_not_partial() for enumname, enumval in zip(tp.enumerators, tp.enumvalues): if enumname not in library.__dict__: library.__dict__[enumname] = enumval diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -1006,6 +1006,8 @@ def _enum_ctx(self, tp, cname): type_index = self._typesdict[tp] type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): self._lsts["global"].append( GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -1,7 +1,7 @@ import py import platform import sys, ctypes -from cffi import FFI, CDefError, FFIError +from cffi import FFI, CDefError, FFIError, VerificationMissing from testing.support import * SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) @@ -926,6 +926,14 @@ assert ffi.string(ffi.cast("enum foo", -16)) == "E" assert ffi.string(ffi.cast("enum foo", -8)) == "F" + def test_enum_partial(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };") + lib = ffi.dlopen(None) + py.test.raises(VerificationMissing, getattr, lib, "A") + assert lib.B == 0 + assert lib.C == 1 + def test_array_of_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a, b; };") diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py --- a/testing/cffi1/test_re_python.py +++ b/testing/cffi1/test_re_python.py @@ -1,7 +1,7 @@ import sys import py from cffi import FFI -from cffi import recompiler, ffiplatform +from cffi import recompiler, ffiplatform, VerificationMissing from testing.udir import udir @@ -203,3 +203,10 @@ "foobar", _version=0x2594) assert str(e.value).startswith( "cffi out-of-line Python module 'foobar' has unknown version") + +def test_partial_enum(): + ffi = FFI() + ffi.cdef("enum foo { A, B, ... };") + ffi.set_source('test_partial_enum', None) + py.test.raises(VerificationMissing, ffi.emit_python_code, + str(tmpdir.join('test_partial_enum.py'))) From noreply at buildbot.pypy.org Wed Sep 23 10:02:59 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 10:02:59 +0200 (CEST) Subject: [pypy-commit] pypy default: add comment Message-ID: <20150923080259.445001C1347@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79781:f18ef9299aaf Date: 2015-09-23 10:03 +0200 http://bitbucket.org/pypy/pypy/changeset/f18ef9299aaf/ Log: add comment diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -784,7 +784,7 @@ 'NEWSTR/1/r', #-> STR, the hash field is zeroed 'NEWUNICODE/1/r', #-> UNICODE, the hash field is zeroed '_MALLOC_LAST', - 'FORCE_TOKEN/0/r', + 'FORCE_TOKEN/0/r', # historical name; nowadays, returns the jitframe 'VIRTUAL_REF/2/r', # removed before it's passed to the backend # this one has no *visible* side effect, since the virtualizable # must be forced, however we need to execute it anyway From noreply at buildbot.pypy.org Wed Sep 23 11:01:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 11:01:23 +0200 (CEST) Subject: [pypy-commit] pypy default: no-op: move around some methods to a more natural class Message-ID: <20150923090123.3E2AE1C0590@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79782:b4e07df5f525 Date: 2015-09-23 11:01 +0200 http://bitbucket.org/pypy/pypy/changeset/b4e07df5f525/ Log: no-op: move around some methods to a more natural class 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 @@ -48,9 +48,6 @@ def is_null(self): return False - def is_virtual(self): - return False - def force_at_the_end_of_preamble(self, op, optforce, rec): if not self.is_virtual(): return optforce.get_box_replacement(op) @@ -110,11 +107,6 @@ self.last_guard_pos = len(optimizer._newoperations) - 1 assert self.get_last_guard(optimizer).is_guard() - def visitor_walk_recursive(self, instbox, visitor, optimizer): - if visitor.already_seen_virtual(instbox): - return - return self._visitor_walk_recursive(instbox, visitor, optimizer) - def make_guards(self, op, short, optimizer): op = ResOperation(rop.GUARD_NONNULL, [op], None) short.append(op) @@ -160,6 +152,15 @@ def is_virtual(self): return self._is_virtual + def _visitor_walk_recursive(self, op, visitor, optimizer): + raise NotImplementedError("abstract") + + def visitor_walk_recursive(self, instbox, visitor, optimizer): + if visitor.already_seen_virtual(instbox): + return + return self._visitor_walk_recursive(instbox, visitor, optimizer) + + class AbstractStructPtrInfo(AbstractVirtualPtrInfo): _attrs_ = ('_fields',) @@ -353,9 +354,6 @@ return visitor.visit_vstruct(self.descr, fielddescrs) class AbstractRawPtrInfo(AbstractVirtualPtrInfo): - def _visitor_walk_recursive(self, op, visitor, optimizer): - raise NotImplementedError("abstract") - @specialize.argtype(1) def visitor_dispatch_virtual_type(self, visitor): raise NotImplementedError("abstract") From noreply at buildbot.pypy.org Wed Sep 23 11:01:48 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 11:01:48 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: disable sharing of guards until we fix obscure crashes Message-ID: <20150923090148.90F161C0590@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79783:e2f8b5254f11 Date: 2015-09-23 11:01 +0200 http://bitbucket.org/pypy/pypy/changeset/e2f8b5254f11/ Log: disable sharing of guards until we fix obscure crashes 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 @@ -499,7 +499,7 @@ def propagate_all_forward(self, inputargs, ops, call_pure_results=None, rename_inputargs=True, flush=True, origin_jitcode=None, origin_pc=0): - self.origin_jitcode = origin_jitcode + self.origin_jitcode = None # origin_jitcode self.origin_pc = origin_pc if rename_inputargs: newargs = [] From noreply at buildbot.pypy.org Wed Sep 23 11:47:39 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 11:47:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix. Hard to figure out how to write a test... Message-ID: <20150923094739.181921C012C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79784:2f49f30cc8d8 Date: 2015-09-23 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/2f49f30cc8d8/ Log: Fix. Hard to figure out how to write a test... 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 @@ -156,6 +156,7 @@ raise NotImplementedError("abstract") def visitor_walk_recursive(self, instbox, visitor, optimizer): + instbox = instbox.get_box_replacement() if visitor.already_seen_virtual(instbox): return return self._visitor_walk_recursive(instbox, visitor, optimizer) @@ -238,7 +239,6 @@ for i in range(len(lst)): op = self._fields[i] if op: - op = op.get_box_replacement() fieldinfo = optimizer.getptrinfo(op) if fieldinfo and fieldinfo.is_virtual(): fieldinfo.visitor_walk_recursive(op, visitor, optimizer) From noreply at buildbot.pypy.org Wed Sep 23 11:48:50 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 11:48:50 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix the test to reflect not removing guards for now Message-ID: <20150923094850.2027D1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79785:00540146c066 Date: 2015-09-23 11:48 +0200 http://bitbucket.org/pypy/pypy/changeset/00540146c066/ Log: fix the test to reflect not removing guards for now 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 @@ -2082,7 +2082,7 @@ assert res == 7068153 self.check_trace_count(6) self.check_resops(guard_true=8, guard_class=2, int_mul=3, - int_add=3, guard_false=3) + int_add=3, guard_false=4) def test_dont_trace_every_iteration(self): myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa']) From noreply at buildbot.pypy.org Wed Sep 23 14:25:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 14:25:51 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: disable replacing guard_class with guard_value because it messes up with sharing, we need to improve sharing to guard class first Message-ID: <20150923122551.9505F1C15B6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79786:daebcacf2da4 Date: 2015-09-23 14:25 +0200 http://bitbucket.org/pypy/pypy/changeset/daebcacf2da4/ Log: disable replacing guard_class with guard_value because it messes up with sharing, we need to improve sharing to guard class first diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -380,8 +380,10 @@ raise InvalidLoop("promote of a virtual") old_guard_op = info.get_last_guard(self.optimizer) if old_guard_op is not None: - op = self.replace_guard_class_with_guard_value(op, info, - old_guard_op) + pass + # disable it for now because of sharing + #op = self.replace_guard_class_with_guard_value(op, info, + # old_guard_op) elif arg0.type == 'f': arg0 = self.get_box_replacement(arg0) if arg0.is_constant(): From noreply at buildbot.pypy.org Wed Sep 23 15:19:32 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 15:19:32 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix tests Message-ID: <20150923131932.9D41A1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79787:7d3c76be15ba Date: 2015-09-23 15:19 +0200 http://bitbucket.org/pypy/pypy/changeset/7d3c76be15ba/ Log: fix tests 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 @@ -2022,6 +2022,7 @@ None) def test_merge_guard_class_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_class(p1, ConstClass(node_vtable)) [i0] @@ -2055,6 +2056,7 @@ self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -2072,6 +2074,7 @@ self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] 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 @@ -2967,6 +2967,7 @@ assert "promote of a virtual" in exc.msg def test_merge_guard_class_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_class(p1, ConstClass(node_vtable)) [i0] @@ -3012,6 +3013,7 @@ #self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS) def test_merge_guard_nonnull_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -3035,6 +3037,7 @@ #self.check_expanded_fail_descr("i0", rop.GUARD_VALUE) def test_merge_guard_nonnull_guard_class_guard_value(self): + py.test.skip("disabled") ops = """ [p1, i0, i1, i2, p2] guard_nonnull(p1) [i0] @@ -5032,9 +5035,10 @@ expected = """ [p0] p20 = getfield_gc_r(p0, descr=nextdescr) - guard_value(p20, ConstPtr(myptr)) [] + guard_nonnull_class(p20, ConstClass(node_vtable)) [] p23 = getfield_gc_r(p20, descr=valuedescr) guard_isnull(p23) [] + guard_value(p20, ConstPtr(myptr)) [] p64 = call_may_force_r(NULL, NULL, descr=plaincalldescr) jump(p0) """ From noreply at buildbot.pypy.org Wed Sep 23 15:19:34 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 15:19:34 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: reenable the removal of guards Message-ID: <20150923131934.BCC411C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79788:910674dee2a4 Date: 2015-09-23 15:19 +0200 http://bitbucket.org/pypy/pypy/changeset/910674dee2a4/ Log: reenable the removal of guards 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 @@ -499,7 +499,7 @@ def propagate_all_forward(self, inputargs, ops, call_pure_results=None, rename_inputargs=True, flush=True, origin_jitcode=None, origin_pc=0): - self.origin_jitcode = None # origin_jitcode + self.origin_jitcode = origin_jitcode self.origin_pc = origin_pc if rename_inputargs: newargs = [] From noreply at buildbot.pypy.org Wed Sep 23 15:22:10 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 15:22:10 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: whack at tests Message-ID: <20150923132211.0088A1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79789:32308eeb3033 Date: 2015-09-23 15:22 +0200 http://bitbucket.org/pypy/pypy/changeset/32308eeb3033/ Log: whack at tests 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 @@ -1479,7 +1479,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_class=0, guard_value=6) + self.check_resops(guard_class=4, guard_value=6) # # The original 'guard_class' is rewritten to be directly 'guard_value'. # Check that this rewrite does not interfere with the descr, which @@ -1544,7 +1544,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4, + self.check_resops(guard_value=4, guard_class=0, guard_nonnull=6, guard_nonnull_class=0, guard_isnull=2) @@ -1572,7 +1572,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4, + self.check_resops(guard_value=4, guard_class=0, guard_nonnull=6, guard_nonnull_class=0, guard_isnull=2) @@ -1604,7 +1604,7 @@ res = self.meta_interp(f, [399], listops=True) assert res == f(399) self.check_resops(guard_class=0, guard_nonnull=6, guard_value=6, - guard_nonnull_class=0, guard_isnull=2) + guard_nonnull_class=4, guard_isnull=2) def test_residual_call_doesnt_lose_info(self): @@ -2082,7 +2082,7 @@ assert res == 7068153 self.check_trace_count(6) self.check_resops(guard_true=8, guard_class=2, int_mul=3, - int_add=3, guard_false=4) + int_add=3, guard_false=3) def test_dont_trace_every_iteration(self): myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa']) From noreply at buildbot.pypy.org Wed Sep 23 17:07:40 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Wed, 23 Sep 2015 17:07:40 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Add missing include for openpty() Message-ID: <20150923150740.5113B1C012C@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: py3.3 Changeset: r79790:4a280d6a4947 Date: 2015-09-23 16:05 +0100 http://bitbucket.org/pypy/pypy/changeset/4a280d6a4947/ Log: Add missing include for openpty() diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -249,7 +249,7 @@ else: includes = ['unistd.h', 'sys/types.h', 'sys/wait.h', 'utime.h', 'sys/time.h', 'sys/times.h', - 'grp.h', 'dirent.h'] + 'grp.h', 'dirent.h', 'pty.h'] libraries = ['util'] eci = ExternalCompilationInfo( includes=includes, From noreply at buildbot.pypy.org Wed Sep 23 17:20:10 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 17:20:10 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: replace int_xxx_ovf with int_xxx if we're optimizing guard_no_overflow away Message-ID: <20150923152010.C96A11C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79791:873fbb58ce3a Date: 2015-09-23 17:18 +0200 http://bitbucket.org/pypy/pypy/changeset/873fbb58ce3a/ Log: replace int_xxx_ovf with int_xxx if we're optimizing guard_no_overflow away 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 @@ -573,6 +573,7 @@ self.origin_jitcode = None self.origin_pc = 0 else: + self.potentially_change_ovf_op_to_no_ovf(op) return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields @@ -612,6 +613,23 @@ self._last_guard_op = None return op + def potentially_change_ovf_op_to_no_ovf(self, op): + # if last emitted operations was int_xxx_ovf and we are not emitting + # a guard_no_overflow change to int_add + if op.getopnum() != rop.GUARD_NO_OVERFLOW: + return + op = self._newoperations[-1] + if not op.is_ovf(): + return + if op.getopnum() == rop.INT_MUL_OVF: + newop = self.replace_op_with(op, rop.INT_MUL) + elif op.getopnum() == rop.INT_ADD_OVF: + newop = self.replace_op_with(op, rop.INT_ADD) + elif op.getopnum() == rop.INT_SUB_OVF: + newop = self.replace_op_with(op, rop.INT_SUB) + else: + assert False + self._newoperations[-1] = newop def _copy_resume_data_from(self, guard_op, last_guard_op): if guard_op.getopnum() in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION): From noreply at buildbot.pypy.org Wed Sep 23 17:20:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 17:20:12 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: don't optimize away guard_overflow Message-ID: <20150923152012.EEE9E1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79792:d5cb860b19b2 Date: 2015-09-23 17:20 +0200 http://bitbucket.org/pypy/pypy/changeset/d5cb860b19b2/ Log: don't optimize away guard_overflow 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 @@ -572,7 +572,7 @@ self.origin_pc == op.rd_frame_info_list.pc): self.origin_jitcode = None self.origin_pc = 0 - else: + elif op.getopnum() != rop.GUARD_OVERFLOW: self.potentially_change_ovf_op_to_no_ovf(op) return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) From noreply at buildbot.pypy.org Wed Sep 23 18:32:41 2015 From: noreply at buildbot.pypy.org (vext01) Date: Wed, 23 Sep 2015 18:32:41 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Close branch py3.3 Message-ID: <20150923163241.E750A1C1C61@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: py3.3 Changeset: r79793:4a637d21541b Date: 2015-09-23 17:33 +0100 http://bitbucket.org/pypy/pypy/changeset/4a637d21541b/ Log: Close branch py3.3 From noreply at buildbot.pypy.org Wed Sep 23 18:41:43 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 18:41:43 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: shuffle code around so we don't flush setfields when guards are optimized away Message-ID: <20150923164143.51EDC1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79794:36135e62ace3 Date: 2015-09-23 18:41 +0200 http://bitbucket.org/pypy/pypy/changeset/36135e62ace3/ Log: shuffle code around so we don't flush setfields when guards are optimized away diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -11,7 +11,7 @@ from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\ - AbstractResOp + AbstractResOp, GuardResOp from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.optimizeopt import info @@ -289,6 +289,19 @@ return cf def emit_operation(self, op): + if op.is_guard(): + assert isinstance(op, GuardResOp) + origin_jitcode = self.optimizer.origin_jitcode + origin_pc = self.optimizer.origin_pc + if origin_jitcode is not None: + if (origin_jitcode is op.rd_frame_info_list.jitcode and + origin_pc == op.rd_frame_info_list.pc): + self.optimizer.origin_jitcode = None + self.optimizer.origin_pc = 0 + elif op.getopnum() != rop.GUARD_OVERFLOW: + self.optimizer.potentially_change_ovf_op_to_no_ovf(op) + return # we optimize the guard + self.emitting_operation(op) self.emit_postponed_op() if (op.is_comparison() or op.is_call_may_force() 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 @@ -107,7 +107,10 @@ self.last_guard_pos = -1 def mark_last_guard(self, optimizer): - if optimizer.getlastop() is None: + if (optimizer.getlastop() is None or + not optimizer.getlastop().is_guard()): + # there can be a really emitted operation that's not a guard + # e.g. a setfield, ignore those return self.last_guard_pos = len(optimizer._newoperations) - 1 assert self.get_last_guard(optimizer).is_guard() 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 @@ -567,14 +567,6 @@ self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS) if op.is_guard(): assert isinstance(op, GuardResOp) - if self.origin_jitcode is not None: - if (self.origin_jitcode is op.rd_frame_info_list.jitcode and - self.origin_pc == op.rd_frame_info_list.pc): - self.origin_jitcode = None - self.origin_pc = 0 - elif op.getopnum() != rop.GUARD_OVERFLOW: - self.potentially_change_ovf_op_to_no_ovf(op) - return # we optimize the guard self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) pendingfields = self.pendingfields self.pendingfields = None @@ -618,6 +610,9 @@ # a guard_no_overflow change to int_add if op.getopnum() != rop.GUARD_NO_OVERFLOW: return + if not self._newoperations: + # got optimized otherwise + return op = self._newoperations[-1] if not op.is_ovf(): return From noreply at buildbot.pypy.org Wed Sep 23 19:06:00 2015 From: noreply at buildbot.pypy.org (richardlancaster) Date: Wed, 23 Sep 2015 19:06:00 +0200 (CEST) Subject: [pypy-commit] pypy py3.3_imp_refactor: Fix tests that erroneously import _imp instead of imp Message-ID: <20150923170600.EA5E91C1C61@cobra.cs.uni-duesseldorf.de> Author: Richard Lancaster Branch: py3.3_imp_refactor Changeset: r79795:4049929bd1cd Date: 2015-09-21 14:10 +0100 http://bitbucket.org/pypy/pypy/changeset/4049929bd1cd/ Log: Fix tests that erroneously import _imp instead of imp diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -33,41 +33,43 @@ return '@TEST.pyc' def test_find_module(self): - import os - file, pathname, description = self.imp.find_module('cmd') + import os, imp + file, pathname, description = imp.find_module('cmd') assert file is not None file.close() assert os.path.exists(pathname) pathname = pathname.lower() assert pathname.endswith('.py') # even if .pyc is up-to-date - assert description in self.imp.get_suffixes() + assert description in imp.get_suffixes() def test_find_module_with_encoding(self): - import sys + import sys, imp sys.path.insert(0, self.udir) try: - file, pathname, description = self.imp.find_module('latin1') + file, pathname, description = imp.find_module('latin1') assert file.encoding == 'iso-8859-1' # - file, pathname, description = self.imp.find_module('fake_latin1') + file, pathname, description = imp.find_module('fake_latin1') assert file.encoding == 'utf-8' finally: del sys.path[0] def test_load_dynamic(self): - raises(ImportError, self.imp.load_dynamic, 'foo', 'bar') - raises(ImportError, self.imp.load_dynamic, 'foo', 'bar', + import imp + raises(ImportError, imp.load_dynamic, 'foo', 'bar') + raises(ImportError, imp.load_dynamic, 'foo', 'bar', open(self.file_module)) def test_suffixes(self): - for suffix, mode, type in self.imp.get_suffixes(): - if mode == self.imp.PY_SOURCE: + import imp + for suffix, mode, type in imp.get_suffixes(): + if mode == imp.PY_SOURCE: assert suffix == '.py' assert type == 'r' - elif mode == self.imp.PY_COMPILED: + elif mode == imp.PY_COMPILED: assert suffix in ('.pyc', '.pyo') assert type == 'rb' - elif mode == self.imp.C_EXTENSION: + elif mode == imp.C_EXTENSION: assert suffix.endswith(('.pyd', '.so')) assert type == 'rb' @@ -76,34 +78,36 @@ assert suffix.endswith(('.pyd', '.so')) def test_obscure_functions(self): - mod = self.imp.new_module('hi') + import imp + mod = imp.new_module('hi') assert mod.__name__ == 'hi' - mod = self.imp.init_builtin('hello.world.this.is.never.a.builtin.module.name') + mod = imp.init_builtin('hello.world.this.is.never.a.builtin.module.name') assert mod is None - mod = self.imp.init_frozen('hello.world.this.is.never.a.frozen.module.name') + mod = imp.init_frozen('hello.world.this.is.never.a.frozen.module.name') assert mod is None - assert self.imp.is_builtin('sys') - assert not self.imp.is_builtin('hello.world.this.is.never.a.builtin.module.name') - assert not self.imp.is_frozen('hello.world.this.is.never.a.frozen.module.name') + assert imp.is_builtin('sys') + assert not imp.is_builtin('hello.world.this.is.never.a.builtin.module.name') + assert not imp.is_frozen('hello.world.this.is.never.a.frozen.module.name') def test_load_module_py(self): + import imp fn = self._py_file() - descr = ('.py', 'U', self.imp.PY_SOURCE) + descr = ('.py', 'U', imp.PY_SOURCE) f = open(fn, 'U') - mod = self.imp.load_module('test_imp_extra_AUTO1', f, fn, descr) + mod = imp.load_module('test_imp_extra_AUTO1', f, fn, descr) f.close() assert mod.MARKER == 42 import test_imp_extra_AUTO1 assert mod is test_imp_extra_AUTO1 def test_load_module_pyc_1(self): - import os + import os, imp fn = self._pyc_file() try: - descr = ('.pyc', 'rb', self.imp.PY_COMPILED) + descr = ('.pyc', 'rb', imp.PY_COMPILED) f = open(fn, 'rb') - mod = self.imp.load_module('test_imp_extra_AUTO2', f, fn, descr) + mod = imp.load_module('test_imp_extra_AUTO2', f, fn, descr) f.close() assert mod.marker == 42 import test_imp_extra_AUTO2 @@ -112,17 +116,18 @@ os.unlink(fn) def test_load_source(self): + import imp fn = self._py_file() - mod = self.imp.load_source('test_imp_extra_AUTO3', fn) + mod = imp.load_source('test_imp_extra_AUTO3', fn) assert mod.MARKER == 42 import test_imp_extra_AUTO3 assert mod is test_imp_extra_AUTO3 def test_load_module_pyc_2(self): - import os + import os, imp fn = self._pyc_file() try: - mod = self.imp.load_compiled('test_imp_extra_AUTO4', fn) + mod = imp.load_compiled('test_imp_extra_AUTO4', fn) assert mod.marker == 42 import test_imp_extra_AUTO4 assert mod is test_imp_extra_AUTO4 @@ -130,30 +135,32 @@ os.unlink(fn) def test_load_broken_pyc(self): + import imp fn = self._py_file() try: - self.imp.load_compiled('test_imp_extra_AUTO5', fn) + imp.load_compiled('test_imp_extra_AUTO5', fn) except ImportError: pass else: raise Exception("expected an ImportError") def test_load_module_in_sys_modules(self): + import imp fn = self._py_file() f = open(fn, 'rb') - descr = ('.py', 'U', self.imp.PY_SOURCE) - mod = self.imp.load_module('test_imp_extra_AUTO6', f, fn, descr) + descr = ('.py', 'U', imp.PY_SOURCE) + mod = imp.load_module('test_imp_extra_AUTO6', f, fn, descr) f.close() f = open(fn, 'rb') - mod2 = self.imp.load_module('test_imp_extra_AUTO6', f, fn, descr) + mod2 = imp.load_module('test_imp_extra_AUTO6', f, fn, descr) f.close() assert mod2 is mod def test_nullimporter(self): - import os - importer = self.imp.NullImporter("path") + import os, imp + importer = imp.NullImporter("path") assert importer.find_module(1, 2, 3, 4) is None - raises(ImportError, self.imp.NullImporter, os.getcwd()) + raises(ImportError, imp.NullImporter, os.getcwd()) def test_path_importer_cache(self): import os From noreply at buildbot.pypy.org Wed Sep 23 19:06:03 2015 From: noreply at buildbot.pypy.org (richardlancaster) Date: Wed, 23 Sep 2015 19:06:03 +0200 (CEST) Subject: [pypy-commit] pypy py3.3_imp_refactor: Close branch py3.3_imp_refactor Message-ID: <20150923170603.0BEEA1C1C61@cobra.cs.uni-duesseldorf.de> Author: richardlancaster Branch: py3.3_imp_refactor Changeset: r79796:0d851c0bf664 Date: 2015-09-23 17:01 +0100 http://bitbucket.org/pypy/pypy/changeset/0d851c0bf664/ Log: Close branch py3.3_imp_refactor From noreply at buildbot.pypy.org Wed Sep 23 19:06:05 2015 From: noreply at buildbot.pypy.org (richardlancaster) Date: Wed, 23 Sep 2015 19:06:05 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: Merge py3.3 test fixes Message-ID: <20150923170605.431B41C1C61@cobra.cs.uni-duesseldorf.de> Author: richardlancaster Branch: py3.3 Changeset: r79797:08d07d081df8 Date: 2015-09-23 17:01 +0100 http://bitbucket.org/pypy/pypy/changeset/08d07d081df8/ Log: Merge py3.3 test fixes * Importing _imp instead of imp diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -33,41 +33,43 @@ return '@TEST.pyc' def test_find_module(self): - import os - file, pathname, description = self.imp.find_module('cmd') + import os, imp + file, pathname, description = imp.find_module('cmd') assert file is not None file.close() assert os.path.exists(pathname) pathname = pathname.lower() assert pathname.endswith('.py') # even if .pyc is up-to-date - assert description in self.imp.get_suffixes() + assert description in imp.get_suffixes() def test_find_module_with_encoding(self): - import sys + import sys, imp sys.path.insert(0, self.udir) try: - file, pathname, description = self.imp.find_module('latin1') + file, pathname, description = imp.find_module('latin1') assert file.encoding == 'iso-8859-1' # - file, pathname, description = self.imp.find_module('fake_latin1') + file, pathname, description = imp.find_module('fake_latin1') assert file.encoding == 'utf-8' finally: del sys.path[0] def test_load_dynamic(self): - raises(ImportError, self.imp.load_dynamic, 'foo', 'bar') - raises(ImportError, self.imp.load_dynamic, 'foo', 'bar', + import imp + raises(ImportError, imp.load_dynamic, 'foo', 'bar') + raises(ImportError, imp.load_dynamic, 'foo', 'bar', open(self.file_module)) def test_suffixes(self): - for suffix, mode, type in self.imp.get_suffixes(): - if mode == self.imp.PY_SOURCE: + import imp + for suffix, mode, type in imp.get_suffixes(): + if mode == imp.PY_SOURCE: assert suffix == '.py' assert type == 'r' - elif mode == self.imp.PY_COMPILED: + elif mode == imp.PY_COMPILED: assert suffix in ('.pyc', '.pyo') assert type == 'rb' - elif mode == self.imp.C_EXTENSION: + elif mode == imp.C_EXTENSION: assert suffix.endswith(('.pyd', '.so')) assert type == 'rb' @@ -76,34 +78,36 @@ assert suffix.endswith(('.pyd', '.so')) def test_obscure_functions(self): - mod = self.imp.new_module('hi') + import imp + mod = imp.new_module('hi') assert mod.__name__ == 'hi' - mod = self.imp.init_builtin('hello.world.this.is.never.a.builtin.module.name') + mod = imp.init_builtin('hello.world.this.is.never.a.builtin.module.name') assert mod is None - mod = self.imp.init_frozen('hello.world.this.is.never.a.frozen.module.name') + mod = imp.init_frozen('hello.world.this.is.never.a.frozen.module.name') assert mod is None - assert self.imp.is_builtin('sys') - assert not self.imp.is_builtin('hello.world.this.is.never.a.builtin.module.name') - assert not self.imp.is_frozen('hello.world.this.is.never.a.frozen.module.name') + assert imp.is_builtin('sys') + assert not imp.is_builtin('hello.world.this.is.never.a.builtin.module.name') + assert not imp.is_frozen('hello.world.this.is.never.a.frozen.module.name') def test_load_module_py(self): + import imp fn = self._py_file() - descr = ('.py', 'U', self.imp.PY_SOURCE) + descr = ('.py', 'U', imp.PY_SOURCE) f = open(fn, 'U') - mod = self.imp.load_module('test_imp_extra_AUTO1', f, fn, descr) + mod = imp.load_module('test_imp_extra_AUTO1', f, fn, descr) f.close() assert mod.MARKER == 42 import test_imp_extra_AUTO1 assert mod is test_imp_extra_AUTO1 def test_load_module_pyc_1(self): - import os + import os, imp fn = self._pyc_file() try: - descr = ('.pyc', 'rb', self.imp.PY_COMPILED) + descr = ('.pyc', 'rb', imp.PY_COMPILED) f = open(fn, 'rb') - mod = self.imp.load_module('test_imp_extra_AUTO2', f, fn, descr) + mod = imp.load_module('test_imp_extra_AUTO2', f, fn, descr) f.close() assert mod.marker == 42 import test_imp_extra_AUTO2 @@ -112,17 +116,18 @@ os.unlink(fn) def test_load_source(self): + import imp fn = self._py_file() - mod = self.imp.load_source('test_imp_extra_AUTO3', fn) + mod = imp.load_source('test_imp_extra_AUTO3', fn) assert mod.MARKER == 42 import test_imp_extra_AUTO3 assert mod is test_imp_extra_AUTO3 def test_load_module_pyc_2(self): - import os + import os, imp fn = self._pyc_file() try: - mod = self.imp.load_compiled('test_imp_extra_AUTO4', fn) + mod = imp.load_compiled('test_imp_extra_AUTO4', fn) assert mod.marker == 42 import test_imp_extra_AUTO4 assert mod is test_imp_extra_AUTO4 @@ -130,30 +135,32 @@ os.unlink(fn) def test_load_broken_pyc(self): + import imp fn = self._py_file() try: - self.imp.load_compiled('test_imp_extra_AUTO5', fn) + imp.load_compiled('test_imp_extra_AUTO5', fn) except ImportError: pass else: raise Exception("expected an ImportError") def test_load_module_in_sys_modules(self): + import imp fn = self._py_file() f = open(fn, 'rb') - descr = ('.py', 'U', self.imp.PY_SOURCE) - mod = self.imp.load_module('test_imp_extra_AUTO6', f, fn, descr) + descr = ('.py', 'U', imp.PY_SOURCE) + mod = imp.load_module('test_imp_extra_AUTO6', f, fn, descr) f.close() f = open(fn, 'rb') - mod2 = self.imp.load_module('test_imp_extra_AUTO6', f, fn, descr) + mod2 = imp.load_module('test_imp_extra_AUTO6', f, fn, descr) f.close() assert mod2 is mod def test_nullimporter(self): - import os - importer = self.imp.NullImporter("path") + import os, imp + importer = imp.NullImporter("path") assert importer.find_module(1, 2, 3, 4) is None - raises(ImportError, self.imp.NullImporter, os.getcwd()) + raises(ImportError, imp.NullImporter, os.getcwd()) def test_path_importer_cache(self): import os From noreply at buildbot.pypy.org Wed Sep 23 19:46:42 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 19:46:42 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix heap.py, but a huge blunder in check_history too, fixing tests Message-ID: <20150923174642.C71FD1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79798:30d0f05cdae5 Date: 2015-09-23 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/30d0f05cdae5/ Log: fix heap.py, but a huge blunder in check_history too, fixing tests diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -540,6 +540,9 @@ def check_consistency_of_branch(operations, seen, check_descr=True): "NOT_RPYTHON" for num, op in enumerate(operations): + if op.is_ovf(): + assert operations[num + 1].getopnum() in (rop.GUARD_NO_OVERFLOW, + rop.GUARD_OVERFLOW) for i in range(op.numargs()): box = op.getarg(i) if not isinstance(box, Const): @@ -750,7 +753,6 @@ return tokens def check_history(self, expected=None, **check): - return insns = {} for op in self.operations: opname = op.getopname() diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -298,9 +298,18 @@ origin_pc == op.rd_frame_info_list.pc): self.optimizer.origin_jitcode = None self.optimizer.origin_pc = 0 + elif op.getopnum() == rop.GUARD_NO_OVERFLOW: + if self.postponed_op: + # XXX is this always the case? + assert self.postponed_op.is_ovf() + newop = self.optimizer.replace_op_with_no_ovf( + self.postponed_op) + self.postponed_op = newop + else: + self.optimizer.potentially_change_ovf_op_to_no_ovf(op) + return # we optimize the guard elif op.getopnum() != rop.GUARD_OVERFLOW: - self.optimizer.potentially_change_ovf_op_to_no_ovf(op) - return # we optimize the guard + return self.emitting_operation(op) self.emit_postponed_op() 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 @@ -616,15 +616,19 @@ op = self._newoperations[-1] if not op.is_ovf(): return + newop = self.replace_op_with_no_ovf(op) + self._newoperations[-1] = newop + + def replace_op_with_no_ovf(self, op): if op.getopnum() == rop.INT_MUL_OVF: - newop = self.replace_op_with(op, rop.INT_MUL) + return self.replace_op_with(op, rop.INT_MUL) elif op.getopnum() == rop.INT_ADD_OVF: - newop = self.replace_op_with(op, rop.INT_ADD) + return self.replace_op_with(op, rop.INT_ADD) elif op.getopnum() == rop.INT_SUB_OVF: - newop = self.replace_op_with(op, rop.INT_SUB) + return self.replace_op_with(op, rop.INT_SUB) else: assert False - self._newoperations[-1] = newop + def _copy_resume_data_from(self, guard_op, last_guard_op): if guard_op.getopnum() in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION): 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 @@ -406,7 +406,7 @@ return externfn(n, n+1) res = self.interp_operations(f, [6]) assert res == 42 - self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0) + self.check_operations_history(int_add=1, int_mul=0, call_i=1, guard_no_exception=0) def test_residual_call_elidable(self): def externfn(x, y): @@ -419,7 +419,7 @@ assert res == 42 # CALL_PURE is not recorded in the history if all-constant args self.check_operations_history(int_add=0, int_mul=0, - call=0, call_pure_i=0) + call_i=0, call_pure_i=0) def test_residual_call_elidable_1(self): @elidable @@ -431,7 +431,7 @@ assert res == 42 # CALL_PURE is recorded in the history if not-all-constant args self.check_operations_history(int_add=1, int_mul=0, - call=0, call_pure_i=1) + call_i=0, call_pure_i=1) def test_residual_call_elidable_2(self): myjitdriver = JitDriver(greens = [], reds = ['n']) @@ -659,11 +659,11 @@ # res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0) assert res == 6 - 4 - 5 - self.check_history(call=0) # because the trace starts in the middle + self.check_history(call_n=0) # because the trace starts in the middle # res = self.meta_interp(f, [60, 84], repeat=7) assert res == 84 - 61 - 62 - self.check_history(call=1) # because the trace starts immediately + self.check_history(call_n=1) # because the trace starts immediately def test_unroll_one_loop_iteration(self): def unroll(code): @@ -685,11 +685,11 @@ res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True) assert res == f(1, 4, 1) - self.check_history(call_assembler=0) + self.check_history(call_assembler_i=0) res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True) assert res == f(1, 4, 2) - self.check_history(call_assembler=1) + self.check_history(call_assembler_i=1) def test_format(self): def f(n): From noreply at buildbot.pypy.org Wed Sep 23 20:11:17 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 20:11:17 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: continue whacking at tests Message-ID: <20150923181117.8944F1C0590@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79799:b23e32603989 Date: 2015-09-23 20:11 +0200 http://bitbucket.org/pypy/pypy/changeset/b23e32603989/ Log: continue whacking at tests 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 @@ -841,7 +841,7 @@ return a.foo * x res = self.interp_operations(f, [42]) assert res == 210 - self.check_operations_history(getfield_gc=1) + self.check_operations_history(getfield_gc_i=1) def test_getfield_immutable(self): class A: @@ -858,7 +858,7 @@ return a.foo * x res = self.interp_operations(f, [42]) assert res == 210 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) def test_setfield_bool(self): class A: @@ -1381,7 +1381,7 @@ return g(a, b) res = self.interp_operations(f, [3, 5]) assert res == 8 - self.check_operations_history(int_add=0, call=1) + self.check_operations_history(int_add=0, call_i=1) def test_listcomp(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst']) @@ -1405,7 +1405,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure=0) + self.check_operations_history(setfield_gc=2, getfield_gc_pure_i=0) def test_oosend_look_inside_only_one(self): class A: @@ -4030,7 +4030,7 @@ rgc.ll_arraycopy(a, b, c, d, e) return 42 self.interp_operations(f, [1, 2, 3]) - self.check_operations_history(call=1, guard_no_exception=0) + self.check_operations_history(call_n=1, guard_no_exception=0) def test_weakref(self): import weakref diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -46,7 +46,9 @@ class FfiCallTests(object): def _run(self, atypes, rtype, avalues, rvalue, - expected_call_release_gil=1, + expected_call_release_gil_i=1, + expected_call_release_gil_f=0, + expected_call_release_gil_n=0, supports_floats=True, supports_longlong=False, supports_singlefloats=False): @@ -141,8 +143,12 @@ # longlong and floats are passed around as longlongs. res = float2longlong(res) assert matching_result(res, rvalue) - self.check_operations_history(call_may_force=0, - call_release_gil=expected_call_release_gil) + self.check_operations_history(call_may_force_i=0, + call_may_force_f=0, + call_may_force_n=0, + call_release_gil_i=expected_call_release_gil_i, + call_release_gil_f=expected_call_release_gil_f, + call_release_gil_n=expected_call_release_gil_n) ################################################## driver = jit.JitDriver(reds=['i'], greens=[]) @@ -168,10 +174,13 @@ def test_simple_call_float(self, **kwds): kwds.setdefault('supports_floats', True) + kwds['expected_call_release_gil_f'] = kwds.pop('expected_call_release_gil', 1) + kwds['expected_call_release_gil_i'] = 0 self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds) def test_simple_call_longlong(self, **kwds): kwds.setdefault('supports_longlong', True) + kwds['expected_call_release_gil_i'] = kwds.pop('expected_call_release_gil', 1) maxint32 = 2147483647 a = r_longlong(maxint32) + 1 b = r_longlong(maxint32) + 2 @@ -179,12 +188,15 @@ def test_simple_call_singlefloat_args(self, **kwds): kwds.setdefault('supports_singlefloats', True) + kwds['expected_call_release_gil_f'] = kwds.pop('expected_call_release_gil', 1) + kwds['expected_call_release_gil_i'] = 0 self._run([types.float] * 2, types.double, [r_singlefloat(10.5), r_singlefloat(31.5)], - -4.5) + -4.5, **kwds) def test_simple_call_singlefloat(self, **kwds): kwds.setdefault('supports_singlefloats', True) + kwds['expected_call_release_gil_i'] = kwds.pop('expected_call_release_gil', 1) self._run([types.float] * 2, types.float, [r_singlefloat(10.5), r_singlefloat(31.5)], r_singlefloat(-4.5), **kwds) @@ -192,10 +204,12 @@ def test_simple_call_longdouble(self): # longdouble is not supported, so we expect NOT to generate a call_release_gil self._run([types.longdouble] * 2, types.longdouble, [12.3, 45.6], 78.9, - expected_call_release_gil=0) + expected_call_release_gil_i=0, expected_call_release_gil_f=0, + ) def test_returns_none(self): - self._run([types.signed] * 2, types.void, [456, 789], None) + self._run([types.signed] * 2, types.void, [456, 789], None, + expected_call_release_gil_i=0, expected_call_release_gil_n=1) def test_returns_signedchar(self): self._run([types.sint8], types.sint8, diff --git a/rpython/jit/metainterp/test/test_immutable.py b/rpython/jit/metainterp/test/test_immutable.py --- a/rpython/jit/metainterp/test/test_immutable.py +++ b/rpython/jit/metainterp/test/test_immutable.py @@ -19,7 +19,7 @@ return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=1, int_add=1) + self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=1, int_add=1) def test_fields_subclass(self): class X(object): @@ -41,7 +41,7 @@ return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=2, + self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=2, int_add=2) def f(x, y): @@ -50,7 +50,7 @@ return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=2, + self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=2, int_add=2) def test_array(self): @@ -66,8 +66,8 @@ return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=1, - getarrayitem_gc=0, getarrayitem_gc_pure=1) + self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, + getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) def test_array_index_error(self): class X(object): @@ -89,8 +89,8 @@ return a.get(index) res = self.interp_operations(f, [2], listops=True) assert res == 30 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=1, - getarrayitem_gc=0, getarrayitem_gc_pure=1) + self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, + getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) def test_array_in_immutable(self): class X(object): @@ -106,8 +106,9 @@ return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=2, - getarrayitem_gc=0, getarrayitem_gc_pure=1, + self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, + getfield_gc_pure_i=1, + getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1, int_add=3) @@ -135,15 +136,15 @@ # res = self.interp_operations(f, [0], disable_optimizations=True) assert res == 42 - self.check_operations_history(getfield_raw_pure=1, - getarrayitem_raw_pure=1, + self.check_operations_history(getfield_raw_pure_i=1, + getarrayitem_raw_pure_i=1, int_mul=1) # # second try, in which we get num=0 constant-folded through f() res = self.interp_operations(f, [-1], disable_optimizations=True) assert res == 42 - self.check_operations_history(getfield_raw_pure=0, - getarrayitem_raw_pure=0, + self.check_operations_history(getfield_raw_pure_i=0, + getarrayitem_raw_pure_i=0, int_mul=0) def test_read_on_promoted(self): diff --git a/rpython/jit/metainterp/test/test_math.py b/rpython/jit/metainterp/test/test_math.py --- a/rpython/jit/metainterp/test/test_math.py +++ b/rpython/jit/metainterp/test/test_math.py @@ -13,31 +13,31 @@ res = self.interp_operations(f, [0.0]) assert res == 0.0 - self.check_operations_history(call_pure=1) + self.check_operations_history(call_pure_f=1) # res = self.interp_operations(f, [25.0]) assert res == 5.0 - self.check_operations_history(call_pure=1) + self.check_operations_history(call_pure_f=1) # res = self.interp_operations(f, [-0.0]) assert str(res) == '-0.0' - self.check_operations_history(call_pure=1) + self.check_operations_history(call_pure_f=1) # res = self.interp_operations(f, [1000000.0]) assert res == 1000.0 - self.check_operations_history(call_pure=1) + self.check_operations_history(call_pure_f=1) # res = self.interp_operations(f, [-1.0]) assert res == -INFINITY - self.check_operations_history(call_pure=0) + self.check_operations_history(call_pure_f=0) # res = self.interp_operations(f, [INFINITY]) assert isinf(res) and not isnan(res) and res > 0.0 - self.check_operations_history(call_pure=0) + self.check_operations_history(call_pure_f=0) # res = self.interp_operations(f, [NAN]) assert isnan(res) and not isinf(res) - self.check_operations_history(call_pure=0) + self.check_operations_history(call_pure_f=0) class TestLLtype(MathTests, LLJitMixin): From noreply at buildbot.pypy.org Wed Sep 23 20:23:46 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 20:23:46 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix numpy Message-ID: <20150923182347.038A01C15B6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79800:0ba17eb0536d Date: 2015-09-23 20:23 +0200 http://bitbucket.org/pypy/pypy/changeset/0ba17eb0536d/ Log: fix numpy diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -32,7 +32,10 @@ def product(s): i = 1 for x in s: - i = ovfcheck(i * x) + try: + i = ovfcheck(i * x) + except OverflowError: + raise return i From noreply at buildbot.pypy.org Wed Sep 23 20:23:49 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 20:23:49 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix some more tests Message-ID: <20150923182349.4A6BC1C15B6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79801:e46a6ebba4a3 Date: 2015-09-23 20:23 +0200 http://bitbucket.org/pypy/pypy/changeset/e46a6ebba4a3/ Log: fix some more tests diff --git a/rpython/jit/metainterp/test/test_rawmem.py b/rpython/jit/metainterp/test/test_rawmem.py --- a/rpython/jit/metainterp/test/test_rawmem.py +++ b/rpython/jit/metainterp/test/test_rawmem.py @@ -30,7 +30,9 @@ return 42 res = self.interp_operations(f, []) assert res == 42 - self.check_operations_history({'call': 2, 'guard_no_exception': 1, + self.check_operations_history({'call_i': 1, + 'call_n': 1, + 'guard_no_exception': 1, 'finish': 1}) def test_raw_storage_int(self): @@ -42,8 +44,9 @@ return res res = self.interp_operations(f, []) assert res == 24 - self.check_operations_history({'call': 2, 'guard_no_exception': 1, - 'raw_store': 1, 'raw_load': 1, + self.check_operations_history({'call_i': 1, 'guard_no_exception': 1, + 'call_n': 1, + 'raw_store': 1, 'raw_load_i': 1, 'finish': 1}) self.metainterp.staticdata.stats.check_resops({'finish': 1}, omit_finish=False) @@ -56,8 +59,9 @@ return res res = self.interp_operations(f, []) assert res == 2.4e15 - self.check_operations_history({'call': 2, 'guard_no_exception': 1, - 'raw_store': 1, 'raw_load': 1, + self.check_operations_history({'call_i': 1, 'guard_no_exception': 1, + 'call_n': 1, + 'raw_store': 1, 'raw_load_f': 1, 'finish': 1}) self.metainterp.staticdata.stats.check_resops({'finish': 1}, omit_finish=False) @@ -70,8 +74,9 @@ return rffi.cast(lltype.Signed, res) res = self.interp_operations(f, []) assert res == 254 - self.check_operations_history({'call': 2, 'guard_no_exception': 1, - 'raw_store': 1, 'raw_load': 1, + self.check_operations_history({'call_n': 1, 'guard_no_exception': 1, + 'call_i': 1, + 'raw_store': 1, 'raw_load_i': 1, 'finish': 1}) self.metainterp.staticdata.stats.check_resops({'finish': 1}, omit_finish=False) @@ -84,8 +89,9 @@ return res res = self.interp_operations(f, []) assert res == 24 - self.check_operations_history({'call': 2, 'guard_no_exception': 1, - 'raw_store': 1, 'raw_load': 1, + self.check_operations_history({'call_n': 1, 'guard_no_exception': 1, + 'call_i': 1, + 'raw_store': 1, 'raw_load_i': 1, 'finish': 1}) self.metainterp.staticdata.stats.check_resops({'finish': 1}, omit_finish=False) diff --git a/rpython/jit/metainterp/test/test_recursive.py b/rpython/jit/metainterp/test/test_recursive.py --- a/rpython/jit/metainterp/test/test_recursive.py +++ b/rpython/jit/metainterp/test/test_recursive.py @@ -28,7 +28,7 @@ return 1 res = self.meta_interp(main, [20], enable_opts='') assert res == main(20) - self.check_history(call=0) + self.check_history(call_i=0) def test_simple_recursion_with_exc(self): myjitdriver = JitDriver(greens=[], reds=['n', 'm']) @@ -592,7 +592,7 @@ i += 1 self.meta_interp(portal, [2], inline=True) - self.check_history(call_assembler=1) + self.check_history(call_assembler_n=1) def test_recursion_cant_call_assembler_directly(self): driver = JitDriver(greens = ['codeno'], reds = ['i', 'j'], @@ -709,7 +709,7 @@ return k self.meta_interp(portal, [2], inline=True) - self.check_history(call_assembler=1) + self.check_history(call_assembler_i=1) def test_directly_call_assembler_raise(self): @@ -735,7 +735,7 @@ raise MyException(1) self.meta_interp(portal, [2], inline=True) - self.check_history(call_assembler=1) + self.check_history(call_assembler_n=1) def test_directly_call_assembler_fail_guard(self): driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'], diff --git a/rpython/jit/metainterp/test/test_slist.py b/rpython/jit/metainterp/test/test_slist.py --- a/rpython/jit/metainterp/test/test_slist.py +++ b/rpython/jit/metainterp/test/test_slist.py @@ -33,7 +33,7 @@ return m res = self.interp_operations(f, [11], listops=True) assert res == 49 - self.check_operations_history(call=3) + self.check_operations_history(call_i=1, call_n=2) def test_list_of_voids(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'lst']) From noreply at buildbot.pypy.org Wed Sep 23 20:30:04 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 20:30:04 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: more tests whacking Message-ID: <20150923183004.486841C1C61@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79802:253aa8690617 Date: 2015-09-23 20:30 +0200 http://bitbucket.org/pypy/pypy/changeset/253aa8690617/ Log: more tests whacking diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -85,10 +85,10 @@ return a.x res = self.interp_operations(fn, [7]) assert res == 7 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) res = self.interp_operations(fn, [-7]) assert res == -7 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) def fn(n, ca, cb): a1.x = n @@ -102,10 +102,10 @@ return a.x + b.x res = self.interp_operations(fn, [7, 0, 1]) assert res == 7 * 2 - self.check_operations_history(getfield_gc=1) + self.check_operations_history(getfield_gc_i=1) res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 - self.check_operations_history(getfield_gc=1) + self.check_operations_history(getfield_gc_i=1) def test_heap_caching_nonnull(self): class A: @@ -151,7 +151,7 @@ return a.x + x1 + x2 res = self.interp_operations(fn, [7]) assert res == 5 * 2 + 7 - self.check_operations_history(getfield_gc=1) + self.check_operations_history(getfield_gc_i=1) def test_heap_caching_dont_store_same(self): class A: @@ -168,10 +168,10 @@ return a.x res = self.interp_operations(fn, [7]) assert res == 7 - self.check_operations_history(getfield_gc=0, setfield_gc=1) + self.check_operations_history(getfield_gc_i=0, setfield_gc=1) res = self.interp_operations(fn, [-7]) assert res == -7 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) def test_array_caching(self): a1 = [0, 0] @@ -187,10 +187,10 @@ return a[0] + x1 res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 - self.check_operations_history(getarrayitem_gc=1) + self.check_operations_history(getarrayitem_gc_i=1) res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 - self.check_operations_history(getarrayitem_gc=1) + self.check_operations_history(getarrayitem_gc_i=1) def fn(n, ca, cb): a1[0] = n @@ -204,10 +204,10 @@ return a[0] + b[0] res = self.interp_operations(fn, [7, 0, 1]) assert res == 7 * 2 - self.check_operations_history(getarrayitem_gc=1) + self.check_operations_history(getarrayitem_gc_i=1) res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 - self.check_operations_history(getarrayitem_gc=1) + self.check_operations_history(getarrayitem_gc_i=1) def test_array_caching_while_tracing_invalidation(self): a1 = [0, 0] @@ -230,7 +230,7 @@ return a[0] + x1 + x2 res = self.interp_operations(fn, [7]) assert res == 5 * 2 + 7 - self.check_operations_history(getarrayitem_gc=1) + self.check_operations_history(getarrayitem_gc_i=1) def test_array_and_getfield_interaction(self): class A: pass @@ -254,7 +254,7 @@ res = self.interp_operations(fn, [7]) assert res == 7 * 2 + 1 self.check_operations_history(setarrayitem_gc=2, setfield_gc=3, - getarrayitem_gc=0, getfield_gc=1) + getarrayitem_gc_i=0, getfield_gc_r=1) def test_promote_changes_heap_cache(self): class A: pass @@ -279,7 +279,8 @@ res = self.interp_operations(fn, [7]) assert res == 7 * 2 + 1 self.check_operations_history(setarrayitem_gc=2, setfield_gc=2, - getarrayitem_gc=0, getfield_gc=2) + getarrayitem_gc_i=0, getfield_gc_i=1, + getfield_gc_r=1) def test_promote_changes_array_cache(self): a1 = [0, 0] @@ -297,10 +298,10 @@ return a[0] + x1 res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 - self.check_operations_history(getarrayitem_gc=0, guard_value=1) + self.check_operations_history(getarrayitem_gc_i=0, guard_value=1) res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 - self.check_operations_history(getarrayitem_gc=0, guard_value=1) + self.check_operations_history(getarrayitem_gc_i=0, guard_value=1) def test_list_caching(self): @@ -319,12 +320,12 @@ return a[0] + x1 res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 - self.check_operations_history(getarrayitem_gc=1, - getfield_gc=1) + self.check_operations_history(getarrayitem_gc_i=1, + getfield_gc_r=1) res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 - self.check_operations_history(getarrayitem_gc=1, - getfield_gc=1) + self.check_operations_history(getarrayitem_gc_i=1, + getfield_gc_r=1) def fn(n, ca, cb): a1[0] = n @@ -340,12 +341,12 @@ return a[0] + b[0] res = self.interp_operations(fn, [7, 0, 1]) assert res == 7 * 2 - self.check_operations_history(getarrayitem_gc=1, - getfield_gc=3) + self.check_operations_history(getarrayitem_gc_i=1, + getfield_gc_r=3) res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 - self.check_operations_history(getarrayitem_gc=1, - getfield_gc=3) + self.check_operations_history(getarrayitem_gc_i=1, + getfield_gc_r=3) def test_list_caching_negative(self): def fn(n): @@ -359,7 +360,7 @@ res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 self.check_operations_history(setarrayitem_gc=2, - setfield_gc=2, call=0) + setfield_gc=2, call_n=0, call_i=0, call_r=0) def test_list_caching_negative_nonzero_init(self): def fn(n): @@ -373,7 +374,7 @@ res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 + 42000 self.check_operations_history(setarrayitem_gc=2, - setfield_gc=0, call=1) + setfield_gc=0, call_r=1) def test_virtualizable_with_array_heap_cache(self): myjitdriver = jit.JitDriver(greens = [], reds = ['n', 'x', 'i', 'frame'], @@ -415,7 +416,8 @@ res = self.meta_interp(f, [10, 1, 1], listops=True) assert res == f(10, 1, 1) - self.check_history(getarrayitem_gc=0, getfield_gc=0) + self.check_history(getarrayitem_gc_i=0, getfield_gc_i=0, + getfield_gc_r=0) def test_heap_caching_array_pure(self): class A(object): @@ -434,10 +436,10 @@ return p.x[0] + p.x[1] res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=0) res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 - self.check_operations_history(getfield_gc=0, getfield_gc_pure=0) + self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=0) def test_heap_caching_and_elidable_function(self): class A: @@ -460,10 +462,10 @@ return z + a.x res = self.interp_operations(fn, [7]) assert res == 7 + 7 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) res = self.interp_operations(fn, [-7]) assert res == -7 + 7 - self.check_operations_history(getfield_gc=0) + self.check_operations_history(getfield_gc_i=0) return def test_heap_caching_multiple_objects(self): @@ -494,10 +496,11 @@ return a1.x + a2.x + gn(a1, a2) res = self.interp_operations(fn, [-7]) assert res == 2 * -7 + 2 * -8 - self.check_operations_history(setfield_gc=4, getfield_gc=0) + self.check_operations_history(setfield_gc=4, getfield_gc_i=0, + getfield_gc_r=0) res = self.interp_operations(fn, [7]) assert res == 4 * 7 - self.check_operations_history(getfield_gc=4) + self.check_operations_history(getfield_gc_i=2, getfield_gc_r=2) def test_heap_caching_multiple_tuples(self): class Gbl(object): From noreply at buildbot.pypy.org Wed Sep 23 20:35:57 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 23 Sep 2015 20:35:57 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix more tests Message-ID: <20150923183557.B3F4E1C1C61@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79803:005c4e465033 Date: 2015-09-23 20:34 +0200 http://bitbucket.org/pypy/pypy/changeset/005c4e465033/ Log: fix more tests diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -517,10 +517,12 @@ return a1[0] + a2[0] + gn(a1, a2) res = self.interp_operations(fn, [7]) assert res == 2 * 7 + 2 * 6 - self.check_operations_history(getfield_gc_pure=0) + self.check_operations_history(getfield_gc_pure_i=0, + getfield_gc_pure_r=0) res = self.interp_operations(fn, [-7]) assert res == 2 * -7 + 2 * -8 - self.check_operations_history(getfield_gc_pure=0) + self.check_operations_history(getfield_gc_pure_i=0, + getfield_gc_pure_r=0) def test_heap_caching_multiple_arrays(self): class Gbl(object): @@ -536,10 +538,10 @@ return a1[0] + a2[0] + a1[0] + a2[0] res = self.interp_operations(fn, [7]) assert res == 2 * 7 + 2 * 6 - self.check_operations_history(getarrayitem_gc=0) + self.check_operations_history(getarrayitem_gc_i=0) res = self.interp_operations(fn, [-7]) assert res == 2 * -7 + 2 * -8 - self.check_operations_history(getarrayitem_gc=0) + self.check_operations_history(getarrayitem_gc_i=0) def test_heap_caching_multiple_arrays_getarrayitem(self): class Gbl(object): @@ -560,7 +562,7 @@ return a1[i] + a2[i] + a1[i] + a2[i] res = self.interp_operations(fn, [0]) assert res == 2 * 7 + 2 * 8 - self.check_operations_history(getarrayitem_gc=2) + self.check_operations_history(getarrayitem_gc_i=2) def test_heap_caching_multiple_lists(self): @@ -580,10 +582,12 @@ return a1[0] + a2[0] + a1[0] + a2[0] res = self.interp_operations(fn, [7]) assert res == 2 * 7 + 2 * 6 - self.check_operations_history(getarrayitem_gc=0, getfield_gc=0) + self.check_operations_history(getarrayitem_gc_i=0, getfield_gc_i=0, + getfield_gc_r=0) res = self.interp_operations(fn, [-7]) assert res == 2 * -7 + 2 * -8 - self.check_operations_history(getarrayitem_gc=0, getfield_gc=0) + self.check_operations_history(getarrayitem_gc_i=0, getfield_gc_i=0, + getfield_gc_r=0) def test_length_caching(self): class Gbl(object): @@ -613,7 +617,7 @@ return len(a[:n]) + x[2] res = self.interp_operations(fn, [3], backendopt=True) assert res == 24 - self.check_operations_history(getarrayitem_gc=0) + self.check_operations_history(getarrayitem_gc_i=0) def test_fold_int_add_ovf(self): def fn(n): @@ -649,12 +653,12 @@ return unerase(a)[0] + unerase(b)[0] res = self.interp_operations(fn, [7, 0, 1]) assert res == 7 * 2 - self.check_operations_history(getarrayitem_gc=0, - getfield_gc=0) + self.check_operations_history(getarrayitem_gc_i=0, + getfield_gc_i=0, getfield_gc_r=0) res = self.interp_operations(fn, [-7, 1, 1]) assert res == -7 * 2 - self.check_operations_history(getarrayitem_gc=0, - getfield_gc=0) + self.check_operations_history(getarrayitem_gc_i=0, + getfield_gc_i=0, getfield_gc_r=0) def test_copy_str_content(self): def fn(n): @@ -664,7 +668,8 @@ return x[0] res = self.interp_operations(fn, [0]) assert res == 1 - self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + self.check_operations_history(getarrayitem_gc_i=0, + getarrayitem_gc_pure_i=0) def test_raise_known_class_no_guard_class(self): def raise_exc(cls): From noreply at buildbot.pypy.org Wed Sep 23 20:53:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 23 Sep 2015 20:53:24 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove the cleverness about not building recursive RawSlicePtrInfos. Message-ID: <20150923185324.70F341C14BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79804:2e8414e8d696 Date: 2015-09-23 20:53 +0200 http://bitbucket.org/pypy/pypy/changeset/2e8414e8d696/ Log: Remove the cleverness about not building recursive RawSlicePtrInfos. It doesn't work because of 'op.getarg(0)' we do in that class, but sometimes we'd need to follow it more than once. diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -256,13 +256,10 @@ offset = offsetbox.getint() # the following check is constant-folded to False if the # translation occurs without any VRawXxxValue instance around - if isinstance(opinfo, info.RawBufferPtrInfo): + if (isinstance(opinfo, info.RawBufferPtrInfo) or + isinstance(opinfo, info.RawSlicePtrInfo)): self.make_virtual_raw_slice(offset, opinfo, op) return - elif isinstance(opinfo, info.RawSlicePtrInfo): - offset = offset + opinfo.offset - self.make_virtual_raw_slice(offset, opinfo.parent, op) - return self.emit_operation(op) def optimize_ARRAYLEN_GC(self, op): From noreply at buildbot.pypy.org Wed Sep 23 21:54:08 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Wed, 23 Sep 2015 21:54:08 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: merge heads Message-ID: <20150923195408.64A5F1C0590@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: py3.3 Changeset: r79805:7ac40865b0ff Date: 2015-09-23 20:54 +0100 http://bitbucket.org/pypy/pypy/changeset/7ac40865b0ff/ Log: merge heads diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -249,7 +249,7 @@ else: includes = ['unistd.h', 'sys/types.h', 'sys/wait.h', 'utime.h', 'sys/time.h', 'sys/times.h', - 'grp.h', 'dirent.h'] + 'grp.h', 'dirent.h', 'pty.h'] libraries = ['util'] eci = ExternalCompilationInfo( includes=includes, @@ -1659,19 +1659,23 @@ finally: lltype.free(l_utsbuf, flavor='raw') +# These are actually macros on some/most systems c_makedev = external('makedev', [rffi.INT, rffi.INT], rffi.INT) c_major = external('major', [rffi.INT], rffi.INT) c_minor = external('minor', [rffi.INT], rffi.INT) @replace_os_function('makedev') + at jit.dont_look_inside def makedev(maj, min): return c_makedev(maj, min) @replace_os_function('major') + at jit.dont_look_inside def major(dev): return c_major(dev) @replace_os_function('minor') + at jit.dont_look_inside def minor(dev): return c_minor(dev) From noreply at buildbot.pypy.org Thu Sep 24 09:46:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 09:46:50 +0200 (CEST) Subject: [pypy-commit] pypy default: Comment Message-ID: <20150924074650.9D8221C14B3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79806:3c4e18e30656 Date: 2015-09-24 09:47 +0200 http://bitbucket.org/pypy/pypy/changeset/3c4e18e30656/ Log: Comment diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -5,8 +5,8 @@ with any external library. Right now, there are the following possibilities of providing -third-party modules for the PyPy python interpreter (in order of -usefulness): +third-party modules for the PyPy python interpreter (in order, from most +directly useful to most messy to use with PyPy): * Write them in pure Python and use CFFI_. From noreply at buildbot.pypy.org Thu Sep 24 10:52:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 10:52:10 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: PPC Backend #5: GC Message-ID: <20150924085210.BA16C1C1455@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79807:293103ba23de Date: 2015-09-24 10:45 +0200 http://bitbucket.org/pypy/pypy/changeset/293103ba23de/ Log: PPC Backend #5: GC Support for a non-testing, non-Boehm GC. Implemented the various kinds of mallocs, the write barriers, and other GC-related code like pushing and popping the gcmap, reloading the jitframe, etc. Update some tests outside the PPC backend, too. diff too long, truncating to 2000 out of 2034 lines diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -26,24 +26,24 @@ # for the individual tests see # ====> ../../test/runner_test.py - add_loop_instructions = ['ldr', 'adds', 'cmp', 'beq', 'b'] - bridge_loop_instructions = ['ldr', 'mov', 'nop', 'cmp', 'bge', - 'push', 'mov', 'mov', 'push', 'mov', 'mov', - 'blx', 'mov', 'mov', 'bx'] + add_loop_instructions = 'ldr; adds; cmp; beq; b;$' + bridge_loop_instructions = ('ldr; mov; nop; cmp; bge; ' + 'push; mov; mov; push; mov; mov; ' + 'blx; mov; mov; bx;$') arch_version = detect_arch_version() if arch_version == 7: - bridge_loop_instructions = ['ldr', 'mov', 'nop', 'cmp', 'bge', - 'push', 'mov', 'mov', 'push', 'mov', 'mov', - 'blx', 'mov', 'mov', 'bx'] + bridge_loop_instructions = ('ldr; mov; nop; cmp; bge; ' + 'push; mov; mov; push; mov; mov; ' + 'blx; mov; mov; bx;$') else: - bridge_loop_instructions = ['ldr', 'mov', 'nop', 'nop', 'nop', 'cmp', 'bge', - 'push', 'ldr', 'mov', - '*', # inline constant - 'push', 'ldr', 'mov', - '*', # inline constant - 'blx', 'ldr', 'mov', - '*', # inline constant - 'bx'] + bridge_loop_instructions = ('ldr; mov; nop; nop; nop; cmp; bge; ' + 'push; ldr; mov; ' + '[^;]+; ' # inline constant + 'push; ldr; mov; ' + '[^;]+; ' # inline constant + 'blx; ldr; mov; ' + '[^;]+; ' # inline constant + 'bx;$') def get_cpu(self): cpu = CPU(rtyper=None, stats=FakeStats()) diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -25,6 +25,12 @@ HAS_CODEMAP = False + done_with_this_frame_descr_int = None # overridden by pyjitpl.py + done_with_this_frame_descr_float = None + done_with_this_frame_descr_ref = None + done_with_this_frame_descr_void = None + exit_frame_with_exception_descr_ref = None + def __init__(self, rtyper, stats, opts, translate_support_code=False, gcdescr=None): assert type(opts) is not bool diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py b/rpython/jit/backend/llsupport/test/test_gc_integration.py --- a/rpython/jit/backend/llsupport/test/test_gc_integration.py +++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py @@ -90,6 +90,8 @@ assert nos == [0, 1, 25] elif self.cpu.backend_name.startswith('arm'): assert nos == [0, 1, 47] + elif self.cpu.backend_name.startswith('ppc64'): + assert nos == [0, 1, 33] else: raise Exception("write the data here") assert frame.jf_frame[nos[0]] @@ -155,6 +157,8 @@ self.nursery = lltype.malloc(NTP, 64, flavor='raw') for i in range(64): self.nursery[i] = NOT_INITIALIZED + self.nursery_words = rffi.cast(rffi.CArrayPtr(lltype.Signed), + self.nursery) self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2, flavor='raw') self.addrs[0] = rffi.cast(lltype.Signed, self.nursery) @@ -263,11 +267,11 @@ # slowpath never called assert gc_ll_descr.calls == [] - def test_malloc_nursery_varsize(self): + def test_malloc_nursery_varsize_nonframe(self): self.cpu = self.getcpu(None) A = lltype.GcArray(lltype.Signed) arraydescr = self.cpu.arraydescrof(A) - arraydescr.tid = 15 + arraydescr.tid = 1515 ops = ''' [i0, i1, i2] p0 = call_malloc_nursery_varsize(0, 8, i0, descr=arraydescr) @@ -283,8 +287,8 @@ assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0 assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 2*WORD + 8*1 # check the nursery content and state - assert gc_ll_descr.nursery[0] == chr(15) - assert gc_ll_descr.nursery[2 * WORD + 8] == chr(15) + assert gc_ll_descr.nursery_words[0] == 1515 + assert gc_ll_descr.nursery_words[2 + 8 // WORD] == 1515 assert gc_ll_descr.addrs[0] == nurs_adr + (((4 * WORD + 8*1 + 5*2) + (WORD - 1)) & ~(WORD - 1)) # slowpath never called assert gc_ll_descr.calls == [] @@ -323,11 +327,11 @@ idx = 1 assert len(frame.jf_gcmap) == expected_size if self.cpu.IS_64_BIT: - assert frame.jf_gcmap[idx] == (1<<29) | (1 << 30) + exp_idx = self.cpu.JITFRAME_FIXED_SIZE + 1 # +1 from i0 else: assert frame.jf_gcmap[idx] exp_idx = self.cpu.JITFRAME_FIXED_SIZE - 32 * idx + 1 # +1 from i0 - assert frame.jf_gcmap[idx] == (1 << (exp_idx + 1)) | (1 << exp_idx) + assert frame.jf_gcmap[idx] == (1 << (exp_idx + 1)) | (1 << exp_idx) self.cpu = self.getcpu(check) ops = ''' @@ -636,7 +640,9 @@ frames.append(frame) new_frame = JITFRAME.allocate(frame.jf_frame_info) gcmap = unpack_gcmap(frame) - if self.cpu.IS_64_BIT: + if self.cpu.backend_name.startswith('ppc64'): + assert gcmap == [30, 31, 32] + elif self.cpu.IS_64_BIT: assert gcmap == [28, 29, 30] elif self.cpu.backend_name.startswith('arm'): assert gcmap == [44, 45, 46] @@ -647,6 +653,8 @@ new_frame.jf_frame[item] = rffi.cast(lltype.Signed, s) assert cpu.gc_ll_descr.gcrootmap.stack[0] == rffi.cast(lltype.Signed, frame) cpu.gc_ll_descr.gcrootmap.stack[0] = rffi.cast(lltype.Signed, new_frame) + print '"Collecting" moved the frame from %d to %d' % ( + i, cpu.gc_ll_descr.gcrootmap.stack[0]) frames.append(new_frame) def check2(i): diff --git a/rpython/jit/backend/ppc/callbuilder.py b/rpython/jit/backend/ppc/callbuilder.py --- a/rpython/jit/backend/ppc/callbuilder.py +++ b/rpython/jit/backend/ppc/callbuilder.py @@ -111,10 +111,23 @@ def push_gcmap(self): - pass # XXX + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just before, ignoring the return + # value r3, if necessary + assert not self.is_call_release_gil + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r3], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) def pop_gcmap(self): - pass # XXX + ssreg = None + gcrootmap = self.asm.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + if gcrootmap.is_shadow_stack and self.is_call_release_gil: + # in this mode, 'ebx' happens to contain the shadowstack + # top at this point, so reuse it instead of loading it again + ssreg = ebx + self.asm._reload_frame_if_necessary(self.mc) def emit_raw_call(self): self.mc.raw_call() diff --git a/rpython/jit/backend/ppc/codebuilder.py b/rpython/jit/backend/ppc/codebuilder.py --- a/rpython/jit/backend/ppc/codebuilder.py +++ b/rpython/jit/backend/ppc/codebuilder.py @@ -1049,20 +1049,26 @@ else: RAW_CALL_REG = r.r12 - def raw_call(self): - """Emit a call to the address stored in the register RAW_CALL_REG.""" + def raw_call(self, call_reg=RAW_CALL_REG): + """Emit a call to the address stored in the register 'call_reg', + which must be either RAW_CALL_REG or r12. This is a regular C + function pointer, which means on big-endian that it is actually + the address of a three-words descriptor. + """ if IS_BIG_ENDIAN: # Load the function descriptor (currently in r2) from memory: # [r2 + 0] -> ctr # [r2 + 16] -> r11 # [r2 + 8] -> r2 (= TOC) assert self.RAW_CALL_REG is r.r2 - self.ld(r.SCRATCH.value, r.r2.value, 0) - self.ld(r.r11.value, r.r2.value, 16) + assert call_reg is r.r2 or call_reg is r.r12 + self.ld(r.SCRATCH.value, call_reg.value, 0) + self.ld(r.r11.value, call_reg.value, 16) self.mtctr(r.SCRATCH.value) - self.ld(r.TOC.value, r.r2.value, 8) # must be last: TOC is r2 + self.ld(r.TOC.value, call_reg.value, 8) # must be last: TOC is r2 elif IS_LITTLE_ENDIAN: assert self.RAW_CALL_REG is r.r12 # 'r12' is fixed by this ABI + assert call_reg is r.r12 self.mtctr(r.r12.value) # Call the function self.bctrl() diff --git a/rpython/jit/backend/ppc/opassembler.py b/rpython/jit/backend/ppc/opassembler.py --- a/rpython/jit/backend/ppc/opassembler.py +++ b/rpython/jit/backend/ppc/opassembler.py @@ -11,14 +11,15 @@ IS_BIG_ENDIAN) from rpython.jit.metainterp.history import (JitCellToken, TargetToken, Box, - AbstractFailDescr, FLOAT, INT, REF) + AbstractFailDescr, FLOAT, INT, REF, + ConstInt) from rpython.rlib.objectmodel import we_are_translated from rpython.jit.backend.ppc.helper.assembler import (Saved_Volatiles) from rpython.jit.backend.ppc.jump import remap_frame_layout from rpython.jit.backend.ppc.codebuilder import (OverwritingBuilder, scratch_reg, PPCBuilder, PPCGuardToken) from rpython.jit.backend.ppc.regalloc import TempPtr, TempInt -from rpython.jit.backend.llsupport import symbolic +from rpython.jit.backend.llsupport import symbolic, jitframe from rpython.jit.backend.llsupport.descr import InteriorFieldDescr, CallDescr from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.rtyper.lltypesystem import rstr, rffi, lltype @@ -26,6 +27,7 @@ from rpython.jit.metainterp.resoperation import rop from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.backend.ppc import callbuilder +from rpython.rlib.rarithmetic import r_uint class IntOpAssembler(object): @@ -391,30 +393,31 @@ [fail_descr_loc] = arglocs ofs = self.cpu.get_ofs_of_frame_field('jf_descr') + ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') + self.mc.load_imm(r.r5, fail_descr_loc.getint()) + + # gcmap logic here: + arglist = op.getarglist() + if arglist and arglist[0].type == REF: + if self._finish_gcmap: + # we're returning with a guard_not_forced_2, and + # additionally we need to say that the result contains + # a reference too: + self._finish_gcmap[0] |= r_uint(1) + gcmap = self._finish_gcmap + else: + gcmap = self.gcmap_for_finish + elif self._finish_gcmap: + # we're returning with a guard_not_forced_2 + gcmap = self._finish_gcmap + else: + gcmap = lltype.nullptr(jitframe.GCMAP) + self.load_gcmap(self.mc, r.r2, gcmap) + self.mc.std(r.r5.value, r.SPP.value, ofs) + self.mc.store(r.r2.value, r.SPP.value, ofs2) - ## XXX: gcmap logic here: - ## arglist = op.getarglist() - ## if arglist and arglist[0].type == REF: - ## if self._finish_gcmap: - ## # we're returning with a guard_not_forced_2, and - ## # additionally we need to say that eax/rax contains - ## # a reference too: - ## self._finish_gcmap[0] |= r_uint(1) - ## gcmap = self._finish_gcmap - ## else: - ## gcmap = self.gcmap_for_finish - ## self.push_gcmap(self.mc, gcmap, store=True) - ## elif self._finish_gcmap: - ## # we're returning with a guard_not_forced_2 - ## gcmap = self._finish_gcmap - ## self.push_gcmap(self.mc, gcmap, store=True) - ## else: - ## # note that the 0 here is redundant, but I would rather - ## # keep that one and kill all the others - ## ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') - ## self.mc.MOV_bi(ofs, 0) # exit function self._call_footer() @@ -527,6 +530,8 @@ def _find_nearby_operation(self, regalloc, delta): return regalloc.operations[regalloc.rm.position + delta] + _COND_CALL_SAVE_REGS = [r.r3, r.r4, r.r5, r.r6, r.r12] + def emit_cond_call(self, op, arglocs, regalloc): fcond = self.guard_success_cc self.guard_success_cc = c.cond_none @@ -536,16 +541,13 @@ jmp_adr = self.mc.get_relative_pos() self.mc.trap() # patched later to a 'bc' - # XXX load_gcmap XXX -> r2 + self.load_gcmap(self.mc, r.r2, regalloc.get_gcmap()) # save away r3, r4, r5, r6, r12 into the jitframe - base_ofs = self.cpu.get_baseofs_of_frame_field() - should_be_saved = self._regalloc.rm.reg_bindings.values() - for gpr in [r.r3, r.r4, r.r5, r.r6, r.r12]: - if gpr not in should_be_saved: - continue - v = self.cpu.all_reg_indexes[gpr.value] - self.mc.std(gpr.value, r.SPP.value, v * WORD + base_ofs) + should_be_saved = [ + reg for reg in self._regalloc.rm.reg_bindings.itervalues() + if reg in self._COND_CALL_SAVE_REGS] + self._push_core_regs_to_jitframe(self.mc, should_be_saved) # # load the 0-to-4 arguments into these registers, with the address of # the function to call into r12 @@ -676,6 +678,7 @@ SIZE2SCALE = dict([(1<<_i, _i) for _i in range(32)]) def _multiply_by_constant(self, loc, multiply_by, scratch_loc): + assert loc.is_reg() if multiply_by == 1: return loc try: @@ -910,9 +913,8 @@ self.mc.addi(r.r4.value, r.r4.value, basesize) self.mc.addi(r.r3.value, r.r2.value, basesize) - cb = callbuilder.CallBuilder(self, imm(self.memcpy_addr), - [r.r3, r.r4, r.r5], None) - cb.emit() + self.mc.load_imm(self.mc.RAW_CALL_REG, self.memcpy_addr) + self.mc.raw_call() class UnicodeOpAssembler(object): @@ -933,15 +935,40 @@ self.propagate_memoryerror_if_r3_is_null() def emit_call_malloc_nursery(self, op, arglocs, regalloc): - # registers r3 and r4 are allocated for this call - assert len(arglocs) == 1 - size = arglocs[0].value + # registers r.RES and r.RSZ are allocated for this call + size_box = op.getarg(0) + assert isinstance(size_box, ConstInt) + size = size_box.getint() gc_ll_descr = self.cpu.gc_ll_descr + gcmap = regalloc.get_gcmap([r.RES, r.RSZ]) self.malloc_cond( gc_ll_descr.get_nursery_free_addr(), gc_ll_descr.get_nursery_top_addr(), - size - ) + size, gcmap) + + def emit_call_malloc_nursery_varsize_frame(self, op, arglocs, regalloc): + # registers r.RES and r.RSZ are allocated for this call + [sizeloc] = arglocs + gc_ll_descr = self.cpu.gc_ll_descr + gcmap = regalloc.get_gcmap([r.RES, r.RSZ]) + self.malloc_cond_varsize_frame( + gc_ll_descr.get_nursery_free_addr(), + gc_ll_descr.get_nursery_top_addr(), + sizeloc, gcmap) + + def emit_call_malloc_nursery_varsize(self, op, arglocs, regalloc): + # registers r.RES and r.RSZ are allocated for this call + [lengthloc] = arglocs + arraydescr = op.getdescr() + itemsize = op.getarg(1).getint() + gc_ll_descr = self.cpu.gc_ll_descr + maxlength = (gc_ll_descr.max_size_of_young_obj - WORD * 2) / itemsize + gcmap = regalloc.get_gcmap([r.RES, r.RSZ]) + self.malloc_cond_varsize( + op.getarg(0).getint(), + gc_ll_descr.get_nursery_free_addr(), + gc_ll_descr.get_nursery_top_addr(), + lengthloc, itemsize, maxlength, gcmap, arraydescr) def emit_debug_merge_point(self, op, arglocs, regalloc): pass @@ -950,7 +977,7 @@ emit_keepalive = emit_debug_merge_point def _write_barrier_fastpath(self, mc, descr, arglocs, regalloc, array=False, - is_frame=False, align_stack=False): + is_frame=False): # Write code equivalent to write_barrier() in the GC: it checks # a flag in the object at arglocs[0], and if set, it calls a # helper piece of assembler. The latter saves registers as needed @@ -999,6 +1026,7 @@ helper_num += 2 if self.wb_slowpath[helper_num] == 0: # tests only assert not we_are_translated() + assert not is_frame self.cpu.gc_ll_descr.write_barrier_descr = descr self._build_wb_slowpath(card_marking_mask != 0, bool(regalloc.fprm.reg_bindings)) @@ -1006,15 +1034,9 @@ # if not is_frame: mc.mr(r.r0.value, loc_base.value) # unusual argument location - if is_frame and align_stack: - XXXX - mc.SUB_ri(esp.value, 16 - WORD) # erase the return address mc.load_imm(r.SCRATCH2, self.wb_slowpath[helper_num]) mc.mtctr(r.SCRATCH2.value) mc.bctrl() - if is_frame and align_stack: - XXXX - mc.ADD_ri(esp.value, 16 - WORD) # erase the return address if card_marking_mask: # The helper ends again with a check of the flag in the object. diff --git a/rpython/jit/backend/ppc/ppc_assembler.py b/rpython/jit/backend/ppc/ppc_assembler.py --- a/rpython/jit/backend/ppc/ppc_assembler.py +++ b/rpython/jit/backend/ppc/ppc_assembler.py @@ -16,7 +16,7 @@ from rpython.jit.backend.ppc.register import JITFRAME_FIXED_SIZE from rpython.jit.metainterp.history import AbstractFailDescr from rpython.jit.metainterp.history import ConstInt, BoxInt -from rpython.jit.backend.llsupport import jitframe +from rpython.jit.backend.llsupport import jitframe, rewrite from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.assembler import (DEBUG_COUNTER, debug_bridge, BaseAssembler) @@ -124,27 +124,23 @@ mc.lfd(reg.value, spp_reg.value, self.OFFSET_SPP_TO_FPR_SAVE_AREA + WORD * i) - def gen_shadowstack_header(self, gcrootmap): - # we need to put two words into the shadowstack: the MARKER_FRAME - # and the address of the frame (fp, actually) - rst = gcrootmap.get_root_stack_top_addr() - self.mc.load_imm(r.r14, rst) - self.mc.load(r.r15.value, r.r14.value, 0) # LD r15 [rootstacktop] + def _call_header_shadowstack(self, gcrootmap): + # we need to put one word into the shadowstack: the jitframe (SPP) + mc = self.mc + mc.load_imm(r.RCS1, gcrootmap.get_root_stack_top_addr()) + mc.load(r.RCS2.value, r.RCS1.value, 0) # ld RCS2, [rootstacktop] # - MARKER = gcrootmap.MARKER_FRAME - self.mc.addi(r.r16.value, r.r15.value, 2 * WORD) # ADD r16, r15, 2*WORD - self.mc.load_imm(r.r17, MARKER) - self.mc.store(r.r17.value, r.r15.value, WORD) # STR MARKER, r15+WORD - self.mc.store(r.SPP.value, r.r15.value, 0) # STR spp, r15 + mc.addi(r.RCS3.value, r.RCS2.value, WORD) # add RCS3, RCS2, WORD + mc.store(r.SPP.value, r.RCS2.value, 0) # std SPP, RCS2 # - self.mc.store(r.r16.value, r.r14.value, 0) # STR r16, [rootstacktop] + mc.store(r.RCS3.value, r.RCS1.value, 0) # std RCS3, [rootstacktop] - def gen_footer_shadowstack(self, gcrootmap, mc): - rst = gcrootmap.get_root_stack_top_addr() - mc.load_imm(r.r14, rst) - mc.load(r.r15.value, r.r14.value, 0) # LD r15, [rootstacktop] - mc.addi(r.r15.value, r.r15.value, -2 * WORD) # SUB r15, r15, 2*WORD - mc.store(r.r15.value, r.r14.value, 0) # STR r15, [rootstacktop] + def _call_footer_shadowstack(self, gcrootmap): + mc = self.mc + mc.load_imm(r.RCS1, gcrootmap.get_root_stack_top_addr()) + mc.load(r.RCS2.value, r.RCS1.value, 0) # ld RCS2, [rootstacktop] + mc.addi(r.RCS2.value, r.RCS2.value, WORD) # sub RCS2, RCS2, WORD + mc.store(r.RCS2.value, r.RCS1.value, 0) # std RCS2, [rootstacktop] def new_stack_loc(self, i, tp): base_ofs = self.cpu.get_baseofs_of_frame_field() @@ -153,41 +149,29 @@ def setup_failure_recovery(self): self.failure_recovery_code = [0, 0, 0, 0] - def _push_all_regs_to_jitframe(self, mc, ignored_regs, withfloats, - callee_only=False): + def _push_core_regs_to_jitframe(self, mc, includes=r.MANAGED_REGS): base_ofs = self.cpu.get_baseofs_of_frame_field() - if callee_only: - regs = PPCRegisterManager.save_around_call_regs - else: - regs = PPCRegisterManager.all_regs - # - for reg in regs: - if reg not in ignored_regs: - v = r.ALL_REG_INDEXES[reg] - mc.std(reg.value, r.SPP.value, base_ofs + v * WORD) - # - if withfloats: - for reg in r.MANAGED_FP_REGS: - v = r.ALL_REG_INDEXES[reg] - mc.stfd(reg.value, r.SPP.value, base_ofs + v * WORD) + for reg in includes: + v = r.ALL_REG_INDEXES[reg] + mc.std(reg.value, r.SPP.value, base_ofs + v * WORD) - def _pop_all_regs_from_jitframe(self, mc, ignored_regs, withfloats, - callee_only=False): + def _push_fp_regs_to_jitframe(self, mc, includes=r.MANAGED_FP_REGS): base_ofs = self.cpu.get_baseofs_of_frame_field() - if callee_only: - regs = PPCRegisterManager.save_around_call_regs - else: - regs = PPCRegisterManager.all_regs - # - for reg in regs: - if reg not in ignored_regs: - v = r.ALL_REG_INDEXES[reg] - mc.ld(reg.value, r.SPP.value, base_ofs + v * WORD) - # - if withfloats: - for reg in r.MANAGED_FP_REGS: - v = r.ALL_REG_INDEXES[reg] - mc.lfd(reg.value, r.SPP.value, base_ofs + v * WORD) + for reg in includes: + v = r.ALL_REG_INDEXES[reg] + mc.stfd(reg.value, r.SPP.value, base_ofs + v * WORD) + + def _pop_core_regs_from_jitframe(self, mc, includes=r.MANAGED_REGS): + base_ofs = self.cpu.get_baseofs_of_frame_field() + for reg in includes: + v = r.ALL_REG_INDEXES[reg] + mc.ld(reg.value, r.SPP.value, base_ofs + v * WORD) + + def _pop_fp_regs_from_jitframe(self, mc, includes=r.MANAGED_FP_REGS): + base_ofs = self.cpu.get_baseofs_of_frame_field() + for reg in includes: + v = r.ALL_REG_INDEXES[reg] + mc.lfd(reg.value, r.SPP.value, base_ofs + v * WORD) def _build_failure_recovery(self, exc, withfloats=False): mc = PPCBuilder() @@ -201,7 +185,9 @@ mc.store(r.r0.value, r.SPP.value, ofs) mc.store(r.r2.value, r.SPP.value, ofs2) - self._push_all_regs_to_jitframe(mc, [], withfloats) + self._push_core_regs_to_jitframe(mc) + if withfloats: + self._push_fp_regs_to_jitframe(mc) if exc: # We might have an exception pending. @@ -236,7 +222,8 @@ ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') mc.store(r.r2.value, r.SPP.value, ofs2) - self._push_all_regs_to_jitframe(mc, [], self.cpu.supports_floats) + self._push_core_regs_to_jitframe(mc) + self._push_fp_regs_to_jitframe(mc) # Save away the LR inside r30 mc.mflr(r.RCS1.value) @@ -251,8 +238,8 @@ # Do the call adr = rffi.cast(lltype.Signed, self.cpu.realloc_frame) - cb = callbuilder.CallBuilder(self, imm(adr), [r.r3, r.r4], r.r3) - cb.emit() + mc.load_imm(mc.RAW_CALL_REG, adr) + mc.raw_call() # The result is stored back into SPP (= r31) mc.mr(r.SPP.value, r.r3.value) @@ -261,11 +248,13 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: - self._load_shadowstack_top_in_ebx(mc, gcrootmap) - mc.MOV_mr((ebx.value, -WORD), eax.value) + mc.load_imm(r.r5, gcrootmap.get_root_stack_top_addr()) + mc.load(r.r5.value, r.r5.value, 0) + mc.store(r.r3.value, r.r5.value, -WORD) mc.mtlr(r.RCS1.value) # restore LR - self._pop_all_regs_from_jitframe(mc, [], self.cpu.supports_floats) + self._pop_core_regs_from_jitframe(mc) + self._pop_fp_regs_from_jitframe(mc) mc.blr() self._frame_realloc_slowpath = mc.materialize(self.cpu, []) @@ -294,6 +283,20 @@ mc.store(excvalloc.value, r.r2.value, 0) mc.store(exctploc.value, r.r2.value, diff) + def _reload_frame_if_necessary(self, mc): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + if gcrootmap: + if gcrootmap.is_shadow_stack: + mc.load_imm(r.SPP, gcrootmap.get_root_stack_top_addr()) + mc.load(r.SPP.value, r.SPP.value, 0) + mc.load(r.SPP.value, r.SPP.value, -WORD) + wbdescr = self.cpu.gc_ll_descr.write_barrier_descr + if gcrootmap and wbdescr: + # frame never uses card marking, so we enforce this is not + # an array + self._write_barrier_fastpath(mc, wbdescr, [r.SPP], regalloc=None, + array=False, is_frame=True) + def _build_cond_call_slowpath(self, supports_floats, callee_only): """ This builds a general call slowpath, for whatever call happens to come. @@ -314,87 +317,113 @@ # because these have already been saved by the caller. Note that # this is not symmetrical: these 5 registers are saved by the caller # but restored here at the end of this function. - self._push_all_regs_to_jitframe(mc, [r.r3, r.r4, r.r5, r.r6, r.r12], - supports_floats, callee_only) + if callee_only: + saved_regs = PPCRegisterManager.save_around_call_regs + else: + saved_regs = PPCRegisterManager.all_regs + self._push_core_regs_to_jitframe(mc, [reg for reg in saved_regs + if reg is not r.r3 and + reg is not r.r4 and + reg is not r.r5 and + reg is not r.r6 and + reg is not r.r12]) + if supports_floats: + self._push_fp_regs_to_jitframe(mc) # Save away the LR inside r30 mc.mflr(r.RCS1.value) # Do the call - cb = callbuilder.CallBuilder(self, r.r12, [r.r3, r.r4, r.r5, r.r6], - None) - cb.emit() + mc.raw_call(r.r12) # Finish - # XXX self._reload_frame_if_necessary(mc, align_stack=True) + self._reload_frame_if_necessary(mc) mc.mtlr(r.RCS1.value) # restore LR - self._pop_all_regs_from_jitframe(mc, [], supports_floats, callee_only) + self._pop_core_regs_from_jitframe(mc, saved_regs) + if supports_floats: + self._pop_fp_regs_from_jitframe(mc) mc.blr() self.mc = None return mc.materialize(self.cpu, []) - def _build_malloc_slowpath(self): - xxxxxxx + def _build_malloc_slowpath(self, kind): + """ While arriving on slowpath, we have a gcmap in r2. + The arguments are passed in r.RES and r.RSZ, as follows: + + kind == 'fixed': nursery_head in r.RES and the size in r.RSZ - r.RES. + + kind == 'str/unicode': length of the string to allocate in r.RES. + + kind == 'var': itemsize in r.RES, length to allocate in r.RSZ, + and tid in r.SCRATCH. + + This function must preserve all registers apart from r.RES and r.RSZ. + On return, r2 must contain the address of nursery_free. + """ + assert kind in ['fixed', 'str', 'unicode', 'var'] mc = PPCBuilder() - frame_size = (len(r.MANAGED_FP_REGS) * WORD - + (BACKCHAIN_SIZE + MAX_REG_PARAMS) * WORD) + self.mc = mc + ofs2 = self.cpu.get_ofs_of_frame_field('jf_gcmap') + mc.store(r.r2.value, r.SPP.value, ofs2) + saved_regs = [reg for reg in r.MANAGED_REGS + if reg is not r.RES and reg is not r.RSZ] + self._push_core_regs_to_jitframe(mc, saved_regs) + self._push_fp_regs_to_jitframe(mc) + # + if kind == 'fixed': + addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() + elif kind == 'str': + addr = self.cpu.gc_ll_descr.get_malloc_fn_addr('malloc_str') + elif kind == 'unicode': + addr = self.cpu.gc_ll_descr.get_malloc_fn_addr('malloc_unicode') + else: + addr = self.cpu.gc_ll_descr.get_malloc_slowpath_array_addr() - mc.make_function_prologue(frame_size) - # managed volatiles are saved below - if self.cpu.supports_floats: - for i in range(len(r.MANAGED_FP_REGS)): - mc.stfd(r.MANAGED_FP_REGS[i].value, r.SP.value, - (BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) - # Values to compute size stored in r3 and r4 - mc.subf(r.RES.value, r.RES.value, r.r4.value) - addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr() - for reg, ofs in PPCRegisterManager.REGLOC_TO_COPY_AREA_OFS.items(): - mc.store(reg.value, r.SPP.value, ofs) - mc.call(rffi.cast(lltype.Signed, addr)) - for reg, ofs in PPCRegisterManager.REGLOC_TO_COPY_AREA_OFS.items(): - mc.load(reg.value, r.SPP.value, ofs) - # restore floats - if self.cpu.supports_floats: - for i in range(len(r.MANAGED_FP_REGS)): - mc.lfd(r.MANAGED_FP_REGS[i].value, r.SP.value, - (BACKCHAIN_SIZE + MAX_REG_PARAMS + i) * WORD) + # Save away the LR inside r30 + mc.mflr(r.RCS1.value) - mc.cmp_op(0, r.RES.value, 0, imm=True) - jmp_pos = mc.currpos() - mc.trap() + if kind == 'fixed': + # compute the size we want + mc.subf(r.r3.value, r.RES.value, r.RSZ.value) + if hasattr(self.cpu.gc_ll_descr, 'passes_frame'): + # for tests only + mc.mr(r.r4.value, r.SPP.value) + elif kind == 'str' or kind == 'unicode': + pass # length is already in r3 + else: + # arguments to the called function are [itemsize, tid, length] + # itemsize is already in r3 + mc.mr(r.r5.value, r.RSZ.value) # length + mc.mr(r.r4.value, r.SCRATCH.value) # tid + + # Do the call + addr = rffi.cast(lltype.Signed, addr) + mc.load_imm(mc.RAW_CALL_REG, addr) + mc.raw_call() + + self._reload_frame_if_necessary(mc) + + # Check that we don't get NULL; if we do, we always interrupt the + # current loop, as a "good enough" approximation (same as + # emit_call_malloc_gc()). + self.propagate_memoryerror_if_r3_is_null() + + mc.mtlr(r.RCS1.value) # restore LR + self._pop_core_regs_from_jitframe(mc, saved_regs) + self._pop_fp_regs_from_jitframe(mc) nursery_free_adr = self.cpu.gc_ll_descr.get_nursery_free_addr() - mc.load_imm(r.r4, nursery_free_adr) - mc.load(r.r4.value, r.r4.value, 0) - - if IS_PPC_32: - ofs = WORD - else: - ofs = WORD * 2 - - with scratch_reg(mc): - mc.load(r.SCRATCH.value, r.SP.value, frame_size + ofs) - mc.mtlr(r.SCRATCH.value) - mc.addi(r.SP.value, r.SP.value, frame_size) + self.mc.load_imm(r.r2, nursery_free_adr) + + # r2 is now the address of nursery_free + # r.RES is still the result of the call done above + # r.RSZ is loaded from [r2], to make the caller's store a no-op here + mc.load(r.RSZ.value, r.r2.value, 0) + # mc.blr() - - # if r3 == 0 we skip the return above and jump to the exception path - offset = mc.currpos() - jmp_pos - pmc = OverwritingBuilder(mc, jmp_pos, 1) - pmc.beq(offset) - pmc.overwrite() - # restore the frame before leaving - with scratch_reg(mc): - mc.load(r.SCRATCH.value, r.SP.value, frame_size + ofs) - mc.mtlr(r.SCRATCH.value) - mc.addi(r.SP.value, r.SP.value, frame_size) - mc.b_abs(self.propagate_exception_path) - - rawstart = mc.materialize(self.cpu, []) - # here we do not need a function descr. This is being only called using - # an internal ABI - self.malloc_slowpath = rawstart + self.mc = None + return mc.materialize(self.cpu, []) def _build_stack_check_slowpath(self): _, _, slowpathaddr = self.cpu.insert_stack_check() @@ -512,54 +541,65 @@ # # This builds a helper function called from the slow path of # write barriers. It must save all registers, and optionally - # all fp registers. It takes its single argument in r0. + # all fp registers. It takes its single argument in r0 + # (or in SPP if 'for_frame'). + if for_frame: + argument_loc = r.SPP + else: + argument_loc = r.r0 + mc = PPCBuilder() old_mc = self.mc self.mc = mc - # - ignored_regs = [reg for reg in r.MANAGED_REGS if not ( - # 'reg' will be pushed if the following is true: - reg in r.VOLATILES or - reg is r.RCS1 or - (withcards and reg is r.RCS2))] - if not for_frame: + + if for_frame: + # This 'for_frame' version is called after a CALL. It does not + # need to save many registers: the registers that are anyway + # destroyed by the call can be ignored (VOLATILES), and the + # non-volatile registers won't be changed here. It only needs + # to save r.RCS1 (used below), r3 and f1 (possible results of + # the call), and two more non-volatile registers (used to store + # the RPython exception that occurred in the CALL, if any). + saved_regs = [r.r3, r.RCS1, r.RCS2, r.RCS3] + saved_fp_regs = [r.f1] + else: # push all volatile registers, push RCS1, and sometimes push RCS2 - self._push_all_regs_to_jitframe(mc, ignored_regs, withfloats) - else: - return #XXXXX - # we have one word to align - mc.SUB_ri(esp.value, 7 * WORD) # align and reserve some space - mc.MOV_sr(WORD, eax.value) # save for later - if self.cpu.supports_floats: - mc.MOVSD_sx(2 * WORD, xmm0.value) # 32-bit: also 3 * WORD - if IS_X86_32: - mc.MOV_sr(4 * WORD, edx.value) - mc.MOV_sr(0, ebp.value) - exc0, exc1 = esi, edi + if withcards: + saved_regs = r.VOLATILES + [r.RCS1, r.RCS2] else: - mc.MOV_rr(edi.value, ebp.value) - exc0, exc1 = ebx, r12 - mc.MOV(RawEspLoc(WORD * 5, REF), exc0) - mc.MOV(RawEspLoc(WORD * 6, INT), exc1) - # note that it's save to store the exception in register, + saved_regs = r.VOLATILES + [r.RCS1] + if withfloats: + saved_fp_regs = r.MANAGED_FP_REGS + else: + saved_fp_regs = [] + + self._push_core_regs_to_jitframe(mc, saved_regs) + self._push_fp_regs_to_jitframe(mc, saved_fp_regs) + + if for_frame: + # note that it's safe to store the exception in register, # since the call to write barrier can't collect # (and this is assumed a bit left and right here, like lack # of _reload_frame_if_necessary) - self._store_and_reset_exception(mc, exc0, exc1) + self._store_and_reset_exception(mc, r.RCS2, r.RCS3) if withcards: - mc.mr(r.RCS2.value, r.r0.value) + mc.mr(r.RCS2.value, argument_loc.value) # # Save the lr into r.RCS1 mc.mflr(r.RCS1.value) # func = rffi.cast(lltype.Signed, func) - cb = callbuilder.CallBuilder(self, imm(func), [r.r0], None) - cb.emit() + mc.mr(r.r3.value, argument_loc.value) + mc.load_imm(mc.RAW_CALL_REG, func) + mc.raw_call() # # Restore lr mc.mtlr(r.RCS1.value) - # + + if for_frame: + self._restore_exception(mc, r.RCS2, r.RCS3) + if withcards: # A final andix before the blr, for the caller. Careful to # not follow this instruction with another one that changes @@ -567,23 +607,10 @@ card_marking_mask = descr.jit_wb_cards_set_singlebyte mc.lbz(r.RCS2.value, r.RCS2.value, descr.jit_wb_if_flag_byteofs) mc.andix(r.RCS2.value, r.RCS2.value, card_marking_mask & 0xFF) - # - if not for_frame: - self._pop_all_regs_from_jitframe(mc, ignored_regs, withfloats) - mc.blr() - else: - XXXXXXX - if IS_X86_32: - mc.MOV_rs(edx.value, 4 * WORD) - if self.cpu.supports_floats: - mc.MOVSD_xs(xmm0.value, 2 * WORD) - mc.MOV_rs(eax.value, WORD) # restore - self._restore_exception(mc, exc0, exc1) - mc.MOV(exc0, RawEspLoc(WORD * 5, REF)) - mc.MOV(exc1, RawEspLoc(WORD * 6, INT)) - mc.LEA_rs(esp.value, 7 * WORD) - mc.RET() + self._pop_core_regs_from_jitframe(mc, saved_regs) + self._pop_fp_regs_from_jitframe(mc, saved_fp_regs) + mc.blr() self.mc = old_mc rawstart = mc.materialize(self.cpu, []) @@ -615,52 +642,6 @@ self.propagate_exception_path = rawstart self.mc = None - # The code generated here serves as an exit stub from - # the executed machine code. - # It is generated only once when the backend is initialized. - # - # The following actions are performed: - # - The fail boxes are filled with the computed values - # (failure_recovery_func) - # - The nonvolatile registers are restored - # - jump back to the calling code - def _gen_exit_path(self): - mc = PPCBuilder() - self._save_managed_regs(mc) - decode_func_addr = llhelper(self.recovery_func_sign, - self.failure_recovery_func) - addr = rffi.cast(lltype.Signed, decode_func_addr) - - # load parameters into parameter registers - # address of state encoding - mc.load(r.RES.value, r.SPP.value, FORCE_INDEX_OFS) - mc.mr(r.r4.value, r.SPP.value) # load spilling pointer - mc.mr(r.r5.value, r.SPP.value) # load managed registers pointer - # - # call decoding function - mc.call(addr) - - # generate return and restore registers - self._gen_epilogue(mc) - - return mc.materialize(self.cpu, [], self.cpu.gc_ll_descr.gcrootmap) - - def _save_managed_regs(self, mc): - """ store managed registers in ENCODING AREA - """ - for i in range(len(r.MANAGED_REGS)): - reg = r.MANAGED_REGS[i] - mc.store(reg.value, r.SPP.value, i * WORD) - FLOAT_OFFSET = len(r.MANAGED_REGS) - for i in range(len(r.MANAGED_FP_REGS)): - fpreg = r.MANAGED_FP_REGS[i] - mc.stfd(fpreg.value, r.SPP.value, (i + FLOAT_OFFSET) * WORD) - - #def gen_bootstrap_code(self, loophead, spilling_area): - # self._insert_stack_check() - # self._make_frame(spilling_area) - # self.mc.b_offset(loophead) - def _call_header(self): if IS_PPC_64 and IS_BIG_ENDIAN: # Reserve space for a function descriptor, 3 words @@ -687,8 +668,7 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: - XXX - self.gen_shadowstack_header(gcrootmap) + self._call_header_shadowstack(gcrootmap) def _call_header_with_stack_check(self): self._call_header() @@ -814,8 +794,7 @@ mc.trap() # placeholder for li(r0, ...) mc.load_imm(r.SCRATCH2, self._frame_realloc_slowpath) mc.mtctr(r.SCRATCH2.value) - #XXXXX: - if we_are_translated(): XXX #self.load_gcmap(mc, gcmap) # -> r2 + self.load_gcmap(mc, r.r2, gcmap) mc.bctrl() self.frame_depth_to_patch.append((patch_pos, mc.currpos())) @@ -927,7 +906,7 @@ operations, self.current_clt.allgcrefs, self.current_clt.frame_info) - self._check_frame_depth(self.mc, "??") + self._check_frame_depth(self.mc, regalloc.get_gcmap()) frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, operations) codeendpos = self.mc.get_relative_pos() self.write_pending_failure_recoveries() @@ -975,14 +954,17 @@ #print "=== Loop start is at %s ===" % hex(r_uint(start)) return start - def load_gcmap(self, mc, gcmap): - # load the current gcmap into register r2 + def load_gcmap(self, mc, reg, gcmap): + # load the current gcmap into register 'reg' ptr = rffi.cast(lltype.Signed, gcmap) - mc.load_imm(r.r2, ptr) + mc.load_imm(reg, ptr) - def push_gcmap(self, mc, gcmap, store): + def push_gcmap(self, mc, gcmap, store=True): + # (called from callbuilder.py and ../llsupport/callbuilder.py) assert store is True - # XXX IGNORED FOR NOW + self.load_gcmap(mc, r.SCRATCH, gcmap) + ofs = self.cpu.get_ofs_of_frame_field('jf_gcmap') + mc.store(r.SCRATCH.value, r.SPP.value, ofs) def break_long_loop(self): # If the loop is too long, the guards in it will jump forward @@ -1003,7 +985,7 @@ startpos = self.mc.currpos() fail_descr, target = self.store_info_on_descr(startpos, guardtok) assert target != 0 - self.load_gcmap(self.mc, gcmap=guardtok.gcmap) # -> r2 + self.load_gcmap(self.mc, r.r2, gcmap=guardtok.gcmap) self.mc.load_imm(r.r0, target) self.mc.mtctr(r.r0.value) self.mc.load_imm(r.r0, fail_descr) @@ -1187,56 +1169,201 @@ self.mc.ld(r.SCRATCH.value, r.SP.value, index) self.regalloc_mov(r.SCRATCH, loc) - def malloc_cond(self, nursery_free_adr, nursery_top_adr, size): + def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, gcmap): assert size & (WORD-1) == 0 # must be correctly aligned - self.mc.load_imm(r.RES, nursery_free_adr) - self.mc.load(r.RES.value, r.RES.value, 0) + # We load into RES the address stored at nursery_free_adr. We + # calculate the new value for nursery_free_adr and store it in + # RSZ. Then we load the address stored in nursery_top_adr + # into SCRATCH. In the rare case where the value in RSZ is + # (unsigned) bigger than the one in SCRATCH we call + # malloc_slowpath. In the common case where malloc_slowpath + # is not called, we must still write RSZ back into + # nursery_free_adr (r2); so we do it always, even if we called + # malloc_slowpath. + + diff = nursery_top_adr - nursery_free_adr + assert _check_imm_arg(diff) + mc = self.mc + mc.load_imm(r.r2, nursery_free_adr) + + mc.load(r.RES.value, r.r2.value, 0) # load nursery_free + mc.load(r.SCRATCH.value, r.r2.value, diff) # load nursery_top if _check_imm_arg(size): - self.mc.addi(r.r4.value, r.RES.value, size) + mc.addi(r.RSZ.value, r.RES.value, size) else: - self.mc.load_imm(r.r4, size) - self.mc.add(r.r4.value, r.RES.value, r.r4.value) + mc.load_imm(r.RSZ, size) + mc.add(r.RSZ.value, r.RES.value, r.RSZ.value) - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, nursery_top_adr) - self.mc.loadx(r.SCRATCH.value, 0, r.SCRATCH.value) - self.mc.cmp_op(0, r.r4.value, r.SCRATCH.value, signed=False) + mc.cmp_op(0, r.RSZ.value, r.SCRATCH.value, signed=False) - fast_jmp_pos = self.mc.currpos() - self.mc.trap() + fast_jmp_pos = mc.currpos() + mc.trap() # conditional jump, patched later - # We load into r3 the address stored at nursery_free_adr. We calculate - # the new value for nursery_free_adr and store in r1 The we load the - # address stored in nursery_top_adr into IP If the value in r4 is - # (unsigned) bigger than the one in ip we conditionally call - # malloc_slowpath in case we called malloc_slowpath, which returns the - # new value of nursery_free_adr in r4 and the adr of the new object in - # r3. - self.mark_gc_roots(self.write_new_force_index(), - use_copy_area=True) + # new value of nursery_free_adr in RSZ and the adr of the new object + # in RES. + self.load_gcmap(mc, r.r2, gcmap) # We are jumping to malloc_slowpath without a call through a function - # descriptor, because it is an internal call and "call" would trash r11 - self.mc.bl_abs(self.malloc_slowpath) + # descriptor, because it is an internal call and "call" would trash + # r2 and r11 + mc.bl_abs(self.malloc_slowpath) - offset = self.mc.currpos() - fast_jmp_pos - pmc = OverwritingBuilder(self.mc, fast_jmp_pos, 1) - pmc.ble(offset) # jump if LE (not GT) + offset = mc.currpos() - fast_jmp_pos + pmc = OverwritingBuilder(mc, fast_jmp_pos, 1) + pmc.bc(7, 1, offset) # jump if LE (not GT), predicted to be true pmc.overwrite() - - with scratch_reg(self.mc): - self.mc.load_imm(r.SCRATCH, nursery_free_adr) - self.mc.storex(r.r4.value, 0, r.SCRATCH.value) - def mark_gc_roots(self, force_index, use_copy_area=False): - if force_index < 0: - return # not needed - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - mark = self._regalloc.get_mark_gc_roots(gcrootmap, use_copy_area) - assert gcrootmap.is_shadow_stack - gcrootmap.write_callshape(mark, force_index) + mc.store(r.RSZ.value, r.r2.value, 0) # store into nursery_free + + def malloc_cond_varsize_frame(self, nursery_free_adr, nursery_top_adr, + sizeloc, gcmap): + diff = nursery_top_adr - nursery_free_adr + assert _check_imm_arg(diff) + mc = self.mc + mc.load_imm(r.r2, nursery_free_adr) + + if sizeloc is r.RES: + mc.mr(r.RSZ.value, r.RES.value) + sizeloc = r.RSZ + + mc.load(r.RES.value, r.r2.value, 0) # load nursery_free + mc.load(r.SCRATCH.value, r.r2.value, diff) # load nursery_top + + mc.add(r.RSZ.value, r.RES.value, sizeloc.value) + + mc.cmp_op(0, r.RSZ.value, r.SCRATCH.value, signed=False) + + fast_jmp_pos = mc.currpos() + mc.trap() # conditional jump, patched later + + # new value of nursery_free_adr in RSZ and the adr of the new object + # in RES. + self.load_gcmap(mc, r.r2, gcmap) + mc.bl_abs(self.malloc_slowpath) + + offset = mc.currpos() - fast_jmp_pos + pmc = OverwritingBuilder(mc, fast_jmp_pos, 1) + pmc.bc(7, 1, offset) # jump if LE (not GT), predicted to be true + pmc.overwrite() + + mc.store(r.RSZ.value, r.r2.value, 0) # store into nursery_free + + def malloc_cond_varsize(self, kind, nursery_free_adr, nursery_top_adr, + lengthloc, itemsize, maxlength, gcmap, + arraydescr): + from rpython.jit.backend.llsupport.descr import ArrayDescr + assert isinstance(arraydescr, ArrayDescr) + + # lengthloc is the length of the array, which we must not modify! + assert lengthloc is not r.RES and lengthloc is not r.RSZ + assert lengthloc.is_reg() + + if maxlength > 2**16-1: + maxlength = 2**16-1 # makes things easier + mc = self.mc + mc.cmp_op(0, lengthloc.value, maxlength, imm=True, signed=False) + + jmp_adr0 = mc.currpos() + mc.trap() # conditional jump, patched later + + # ------------------------------------------------------------ + # block of code for the case: the length is <= maxlength + + diff = nursery_top_adr - nursery_free_adr + assert _check_imm_arg(diff) + mc.load_imm(r.r2, nursery_free_adr) + + varsizeloc = self._multiply_by_constant(lengthloc, itemsize, + r.RSZ) + # varsizeloc is either RSZ here, or equal to lengthloc if + # itemsize == 1. It is the size of the variable part of the + # array, in bytes. + + mc.load(r.RES.value, r.r2.value, 0) # load nursery_free + mc.load(r.SCRATCH.value, r.r2.value, diff) # load nursery_top + + assert arraydescr.basesize >= self.gc_minimal_size_in_nursery + constsize = arraydescr.basesize + self.gc_size_of_header + force_realignment = (itemsize % WORD) != 0 + if force_realignment: + constsize += WORD - 1 + mc.addi(r.RSZ.value, r.RSZ.value, constsize) + if force_realignment: + # "& ~(WORD-1)" + bit_limit = 60 if WORD == 8 else 61 + mc.rldicr(r.RSZ.value, r.RSZ.value, 0, bit_limit) + + mc.add(r.RSZ.value, r.RES.value, r.RSZ.value) + # now RSZ contains the total size in bytes, rounded up to a multiple + # of WORD, plus nursery_free_adr + + mc.cmp_op(0, r.RSZ.value, r.SCRATCH.value, signed=False) + + jmp_adr1 = mc.currpos() + mc.trap() # conditional jump, patched later + + # ------------------------------------------------------------ + # block of code for two cases: either the length is > maxlength + # (jump from jmp_adr0), or the length is small enough but there + # is not enough space in the nursery (fall-through) + # + offset = mc.currpos() - jmp_adr0 + pmc = OverwritingBuilder(mc, jmp_adr0, 1) + pmc.bgt(offset) # jump if GT + pmc.overwrite() + # + # save the gcmap + self.load_gcmap(mc, r.r2, gcmap) + # + # load the function to call into CTR + if kind == rewrite.FLAG_ARRAY: + addr = self.malloc_slowpath_varsize + elif kind == rewrite.FLAG_STR: + addr = self.malloc_slowpath_str + elif kind == rewrite.FLAG_UNICODE: + addr = self.malloc_slowpath_unicode + else: + raise AssertionError(kind) + mc.load_imm(r.SCRATCH, addr) + mc.mtctr(r.SCRATCH.value) + # + # load the argument(s) + if kind == rewrite.FLAG_ARRAY: + mc.mr(r.RSZ.value, lengthloc.value) + mc.load_imm(r.RES, itemsize) + mc.load_imm(r.SCRATCH, arraydescr.tid) + else: + mc.mr(r.RES.value, lengthloc.value) + # + # call! + mc.bctrl() + + jmp_location = mc.currpos() + mc.trap() # jump forward, patched later + + # ------------------------------------------------------------ + # block of code for the common case: the length is <= maxlength + # and there is enough space in the nursery + + offset = mc.currpos() - jmp_adr1 + pmc = OverwritingBuilder(mc, jmp_adr1, 1) + pmc.ble(offset) # jump if LE + pmc.overwrite() + # + # write down the tid, but only in this case (not in other cases + # where r.RES is the result of the CALL) + mc.load_imm(r.SCRATCH, arraydescr.tid) + mc.store(r.SCRATCH.value, r.RES.value, 0) + # while we're at it, this line is not needed if we've done the CALL + mc.store(r.RSZ.value, r.r2.value, 0) # store into nursery_free + + # ------------------------------------------------------------ + + offset = mc.currpos() - jmp_location + pmc = OverwritingBuilder(mc, jmp_location, 1) + pmc.b(offset) # jump always + pmc.overwrite() def propagate_memoryerror_if_r3_is_null(self): # if self.propagate_exception_path == 0 (tests), this may jump to 0 diff --git a/rpython/jit/backend/ppc/regalloc.py b/rpython/jit/backend/ppc/regalloc.py --- a/rpython/jit/backend/ppc/regalloc.py +++ b/rpython/jit/backend/ppc/regalloc.py @@ -24,9 +24,11 @@ from rpython.jit.backend.llsupport.descr import unpack_arraydescr from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr +from rpython.jit.backend.llsupport.gcmap import allocate_gcmap from rpython.rlib.objectmodel import we_are_translated from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.rlib import rgc +from rpython.rlib.rarithmetic import r_uint LIMIT_LOOP_BREAK = 15000 # should be much smaller than 32 KB @@ -56,7 +58,8 @@ class FPRegisterManager(RegisterManager): all_regs = r.MANAGED_FP_REGS box_types = [FLOAT] - save_around_call_regs = [_r for _r in all_regs if _r in r.VOLATILES_FLOAT] + save_around_call_regs = r.VOLATILES_FLOAT + assert set(save_around_call_regs).issubset(all_regs) def convert_to_imm(self, c): assert isinstance(c, ConstFloat) @@ -93,8 +96,9 @@ all_regs = r.MANAGED_REGS box_types = None # or a list of acceptable types no_lower_byte_regs = all_regs - save_around_call_regs = [_r for _r in all_regs if _r in r.VOLATILES] + save_around_call_regs = r.VOLATILES frame_reg = r.SPP + assert set(save_around_call_regs).issubset(all_regs) REGLOC_TO_COPY_AREA_OFS = { r.r5: MY_COPY_OF_REGS + 0 * WORD, @@ -349,9 +353,24 @@ while self.min_bytes_before_label > mc.get_relative_pos(): mc.nop() - def get_gcmap(self, noregs=False): - #xxxxxx - return '???' + def get_gcmap(self, forbidden_regs=[], noregs=False): + frame_depth = self.fm.get_frame_depth() + gcmap = allocate_gcmap(self.assembler, frame_depth, + r.JITFRAME_FIXED_SIZE) + for box, loc in self.rm.reg_bindings.iteritems(): + if loc in forbidden_regs: + continue + if box.type == REF and self.rm.is_still_alive(box): + assert not noregs + assert loc.is_reg() + val = self.assembler.cpu.all_reg_indexes[loc.value] + gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8)) + for box, loc in self.fm.bindings.iteritems(): + if box.type == REF and self.rm.is_still_alive(box): + assert isinstance(loc, locations.StackLocation) + val = loc.get_position() + r.JITFRAME_FIXED_SIZE + gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8)) + return gcmap def loc(self, var): if var.type == FLOAT: @@ -921,36 +940,46 @@ return args def prepare_call_malloc_nursery(self, op): - size_box = op.getarg(0) - assert isinstance(size_box, ConstInt) - size = size_box.getint() + self.rm.force_allocate_reg(op.result, selected_reg=r.RES) + self.rm.temp_boxes.append(op.result) + tmp_box = TempInt() + self.rm.force_allocate_reg(tmp_box, selected_reg=r.RSZ) + self.rm.temp_boxes.append(tmp_box) + return [] - self.rm.force_allocate_reg(op.result, selected_reg=r.r3) - t = TempInt() - self.rm.force_allocate_reg(t, selected_reg=r.r4) - self.possibly_free_var(op.result) - self.possibly_free_var(t) - return [imm(size)] + def prepare_call_malloc_nursery_varsize_frame(self, op): + sizeloc = self.ensure_reg(op.getarg(0)) + # sizeloc must be in a register, but we can free it now + # (we take care explicitly of conflicts with r.RES or r.RSZ) + self.free_op_vars() + # the result will be in r.RES + self.rm.force_allocate_reg(op.result, selected_reg=r.RES) + self.rm.temp_boxes.append(op.result) + # we need r.RSZ as a temporary + tmp_box = TempInt() + self.rm.force_allocate_reg(tmp_box, selected_reg=r.RSZ) + self.rm.temp_boxes.append(tmp_box) + return [sizeloc] - def get_mark_gc_roots(self, gcrootmap, use_copy_area=False): - shape = gcrootmap.get_basic_shape() - for v, val in self.frame_manager.bindings.items(): - if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - assert val.is_stack() - gcrootmap.add_frame_offset(shape, val.value) - for v, reg in self.rm.reg_bindings.items(): - gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap - assert gcrootmap is not None and gcrootmap.is_shadow_stack - if reg is r.r3: - continue - if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)): - assert use_copy_area - xxxxxxxxxx # check REGLOC_TO_COPY_AREA_OFS - assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS - area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg] - gcrootmap.add_frame_offset(shape, area_offset) - return gcrootmap.compress_callshape(shape, - self.assembler.datablockwrapper) + def prepare_call_malloc_nursery_varsize(self, op): + gc_ll_descr = self.assembler.cpu.gc_ll_descr + if not hasattr(gc_ll_descr, 'max_size_of_young_obj'): + raise Exception("unreachable code") + # for boehm, this function should never be called + # the result will be in r.RES + self.rm.force_allocate_reg(op.result, selected_reg=r.RES) + self.rm.temp_boxes.append(op.result) + # we need r.RSZ as a temporary + tmp_box = TempInt() + self.rm.force_allocate_reg(tmp_box, selected_reg=r.RSZ) + self.rm.temp_boxes.append(tmp_box) + # length_box always survives: it's typically also present in the + # next operation that will copy it inside the new array. Make + # sure it is in a register different from r.RES and r.RSZ. (It + # should not be a ConstInt at all.) + length_box = op.getarg(2) + lengthloc = self.ensure_reg(length_box) + return [lengthloc] prepare_debug_merge_point = void prepare_jit_debug = void diff --git a/rpython/jit/backend/ppc/register.py b/rpython/jit/backend/ppc/register.py --- a/rpython/jit/backend/ppc/register.py +++ b/rpython/jit/backend/ppc/register.py @@ -14,14 +14,15 @@ NONVOLATILES = [r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31] -VOLATILES = [r0, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12] -# volatile r2 is persisted around calls and r13 can be ignored +VOLATILES = [r3, r4, r5, r6, r7, r8, r9, r10, r11, r12] +# volatiles r0 and r2 are special, and r13 should be fully ignored # we don't use any non-volatile float register, to keep the frame header # code short-ish #NONVOLATILES_FLOAT = [f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, # f24, f25, f26, f27, f28, f29, f30, f31] -VOLATILES_FLOAT = [f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13] +VOLATILES_FLOAT = [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13] +# volatile f0 is special SCRATCH = r0 SCRATCH2 = r2 @@ -33,17 +34,19 @@ RCS1 = r30 # a random managed non-volatile register RCS2 = r29 # a random managed non-volatile register RCS3 = r28 # a random managed non-volatile register +RSZ = r25 # size argument to malloc_slowpath MANAGED_REGS = [r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r25, r26, r27, r28, r29, r30] # registers r14 to r24 are not touched, we have enough # registers already -MANAGED_FP_REGS = VOLATILES_FLOAT[1:] #+ NONVOLATILES_FLOAT +MANAGED_FP_REGS = VOLATILES_FLOAT #+ NONVOLATILES_FLOAT assert RCS1 in MANAGED_REGS and RCS1 in NONVOLATILES assert RCS2 in MANAGED_REGS and RCS2 in NONVOLATILES assert RCS3 in MANAGED_REGS and RCS3 in NONVOLATILES +assert RSZ in MANAGED_REGS # The JITFRAME_FIXED_SIZE is measured in words, and should be the diff --git a/rpython/jit/backend/ppc/runner.py b/rpython/jit/backend/ppc/runner.py --- a/rpython/jit/backend/ppc/runner.py +++ b/rpython/jit/backend/ppc/runner.py @@ -18,6 +18,7 @@ # missing: supports_singlefloats IS_64_BIT = True + backend_name = 'ppc64' from rpython.jit.backend.ppc.register import JITFRAME_FIXED_SIZE frame_reg = r.SP diff --git a/rpython/jit/backend/ppc/test/conftest.py b/rpython/jit/backend/ppc/test/conftest.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/ppc/test/conftest.py @@ -0,0 +1,12 @@ +""" +This conftest disables the backend tests on non PPC platforms +""" +import py, os +from rpython.jit.backend import detect_cpu + +cpu = detect_cpu.autodetect() + +def pytest_collect_directory(path, parent): + if not cpu.startswith('ppc'): + py.test.skip("PPC tests skipped: cpu is %r" % (cpu,)) +pytest_collect_file = pytest_collect_directory diff --git a/rpython/jit/backend/ppc/test/test_calling_convention.py b/rpython/jit/backend/ppc/test/test_calling_convention.py --- a/rpython/jit/backend/ppc/test/test_calling_convention.py +++ b/rpython/jit/backend/ppc/test/test_calling_convention.py @@ -1,9 +1,16 @@ -from rpython.rtyper.annlowlevel import llhelper -from rpython.jit.metainterp.history import JitCellToken -from rpython.jit.backend.test.calling_convention_test import CallingConvTests, parse -from rpython.rtyper.lltypesystem import lltype -from rpython.jit.codewriter.effectinfo import EffectInfo +from rpython.jit.backend.test.calling_convention_test import CallingConvTests +from rpython.jit.backend.ppc.codebuilder import PPCBuilder +import rpython.jit.backend.ppc.register as r + class TestPPCCallingConvention(CallingConvTests): # ../../test/calling_convention_test.py - pass + + def make_function_returning_stack_pointer(self): + mc = PPCBuilder() + mc.mr(r.r3.value, r.r1.value) + mc.blr() + return mc.materialize(self.cpu, []) + + def get_alignment_requirements(self): + return 16 diff --git a/rpython/jit/backend/ppc/test/test_gc_integration.py b/rpython/jit/backend/ppc/test/test_gc_integration.py deleted file mode 100644 --- a/rpython/jit/backend/ppc/test/test_gc_integration.py +++ /dev/null @@ -1,403 +0,0 @@ - -""" Tests for register allocation for common constructs -""" - -import py -from rpython.jit.metainterp.history import BoxInt, ConstInt,\ - BoxPtr, ConstPtr, TreeLoop, TargetToken -from rpython.jit.metainterp.resoperation import rop, ResOperation -from rpython.jit.codewriter import heaptracker -from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.backend.llsupport.descr import GcCache, FieldDescr, FLAG_SIGNED -from rpython.jit.backend.llsupport.gc import GcLLDescription -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.backend.ppc.regalloc import Regalloc -from rpython.jit.backend.ppc.arch import WORD -from rpython.jit.tool.oparser import parse -from rpython.rtyper.lltypesystem import lltype, llmemory, rffi -from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import rclass, rstr -from rpython.jit.backend.llsupport.gc import GcLLDescr_framework - -from rpython.jit.backend.arm.test.test_regalloc import MockAssembler -from rpython.jit.backend.ppc.test.test_regalloc import BaseTestRegalloc -from rpython.jit.backend.ppc.regalloc import PPCRegisterManager, PPCFrameManager,\ - FPRegisterManager - -CPU = getcpuclass() - -class MockGcRootMap(object): - is_shadow_stack = False - def get_basic_shape(self): - return ['shape'] - def add_frame_offset(self, shape, offset): - shape.append(offset) - def add_callee_save_reg(self, shape, reg_index): - index_to_name = { 1: 'ebx', 2: 'esi', 3: 'edi' } - shape.append(index_to_name[reg_index]) - def compress_callshape(self, shape, datablockwrapper): - assert datablockwrapper == 'fakedatablockwrapper' - assert shape[0] == 'shape' - return ['compressed'] + shape[1:] - -class MockGcDescr(GcCache): - get_malloc_slowpath_addr = None - write_barrier_descr = None - moving_gc = True - gcrootmap = MockGcRootMap() - - def initialize(self): - pass - - _record_constptrs = GcLLDescr_framework._record_constptrs.im_func - rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func - -class TestRegallocGcIntegration(BaseTestRegalloc): - - cpu = CPU(None, None) - cpu.gc_ll_descr = MockGcDescr(False) - cpu.setup_once() - - S = lltype.GcForwardReference() - S.become(lltype.GcStruct('S', ('field', lltype.Ptr(S)), - ('int', lltype.Signed))) - - fielddescr = cpu.fielddescrof(S, 'field') - - struct_ptr = lltype.malloc(S) - struct_ref = lltype.cast_opaque_ptr(llmemory.GCREF, struct_ptr) - child_ptr = lltype.nullptr(S) - struct_ptr.field = child_ptr - - - descr0 = cpu.fielddescrof(S, 'int') - ptr0 = struct_ref - - targettoken = TargetToken() - - namespace = locals().copy() - - def test_basic(self): - ops = ''' - [p0] - p1 = getfield_gc(p0, descr=fielddescr) - finish(p1) - ''' - self.interpret(ops, [self.struct_ptr]) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_rewrite_constptr(self): - ops = ''' - [] - p1 = getfield_gc(ConstPtr(struct_ref), descr=fielddescr) - finish(p1) - ''' - self.interpret(ops, []) - assert not self.getptr(0, lltype.Ptr(self.S)) - - def test_bug_0(self): - ops = ''' - [i0, i1, i2, i3, i4, i5, i6, i7, i8] - label(i0, i1, i2, i3, i4, i5, i6, i7, i8, descr=targettoken) - guard_value(i2, 1) [i2, i3, i4, i5, i6, i7, i0, i1, i8] - guard_class(i4, 138998336) [i4, i5, i6, i7, i0, i1, i8] - i11 = getfield_gc(i4, descr=descr0) - guard_nonnull(i11) [i4, i5, i6, i7, i0, i1, i11, i8] - i13 = getfield_gc(i11, descr=descr0) - guard_isnull(i13) [i4, i5, i6, i7, i0, i1, i11, i8] - i15 = getfield_gc(i4, descr=descr0) - i17 = int_lt(i15, 0) - guard_false(i17) [i4, i5, i6, i7, i0, i1, i11, i15, i8] - i18 = getfield_gc(i11, descr=descr0) - i19 = int_ge(i15, i18) - guard_false(i19) [i4, i5, i6, i7, i0, i1, i11, i15, i8] - i20 = int_lt(i15, 0) - guard_false(i20) [i4, i5, i6, i7, i0, i1, i11, i15, i8] - i21 = getfield_gc(i11, descr=descr0) - i22 = getfield_gc(i11, descr=descr0) - i23 = int_mul(i15, i22) - i24 = int_add(i21, i23) - i25 = getfield_gc(i4, descr=descr0) - i27 = int_add(i25, 1) - setfield_gc(i4, i27, descr=descr0) - i29 = getfield_raw(144839744, descr=descr0) - i31 = int_and(i29, -2141192192) - i32 = int_is_true(i31) - guard_false(i32) [i4, i6, i7, i0, i1, i24] - i33 = getfield_gc(i0, descr=descr0) - guard_value(i33, ConstPtr(ptr0)) [i4, i6, i7, i0, i1, i33, i24] - jump(i0, i1, 1, 17, i4, ConstPtr(ptr0), i6, i7, i24, descr=targettoken) - ''' - self.interpret(ops, [0, 0, 0, 0, 0, 0, 0, 0, 0], run=False) - -NOT_INITIALIZED = chr(0xdd) - -class GCDescrFastpathMalloc(GcLLDescription): - gcrootmap = None - write_barrier_descr = None - - def __init__(self): - GcLLDescription.__init__(self, None) - # create a nursery - NTP = rffi.CArray(lltype.Char) - self.nursery = lltype.malloc(NTP, 64, flavor='raw') - for i in range(64): - self.nursery[i] = NOT_INITIALIZED - self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2, - flavor='raw') - self.addrs[0] = rffi.cast(lltype.Signed, self.nursery) - self.addrs[1] = self.addrs[0] + 64 - self.calls = [] - def malloc_slowpath(size): - if self.gcrootmap is not None: # hook - self.gcrootmap.hook_malloc_slowpath() - self.calls.append(size) - # reset the nursery - nadr = rffi.cast(lltype.Signed, self.nursery) - self.addrs[0] = nadr + size - return nadr - self.generate_function('malloc_nursery', malloc_slowpath, - [lltype.Signed], lltype.Signed) - - def get_nursery_free_addr(self): - return rffi.cast(lltype.Signed, self.addrs) - - def get_nursery_top_addr(self): - return rffi.cast(lltype.Signed, self.addrs) + WORD - - def get_malloc_slowpath_addr(self): - return self.get_malloc_fn_addr('malloc_nursery') - - def check_nothing_in_nursery(self): - # CALL_MALLOC_NURSERY should not write anything in the nursery - for i in range(64): - assert self.nursery[i] == NOT_INITIALIZED - -class TestMallocFastpath(BaseTestRegalloc): - - def setup_method(self, method): - cpu = CPU(None, None) - cpu.gc_ll_descr = GCDescrFastpathMalloc() - cpu.setup_once() - self.cpu = cpu - - def test_malloc_fastpath(self): - ops = ''' - [] - p0 = call_malloc_nursery(16) - p1 = call_malloc_nursery(32) - p2 = call_malloc_nursery(16) - finish(p0, p1, p2) - ''' - self.interpret(ops, []) - # check the returned pointers - gc_ll_descr = self.cpu.gc_ll_descr - nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery) - ref = self.cpu.get_latest_value_ref - assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0 - assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16 - assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 48 - # check the nursery content and state - gc_ll_descr.check_nothing_in_nursery() - assert gc_ll_descr.addrs[0] == nurs_adr + 64 - # slowpath never called - assert gc_ll_descr.calls == [] - - def test_malloc_slowpath(self): - ops = ''' - [] - p0 = call_malloc_nursery(16) - p1 = call_malloc_nursery(32) - p2 = call_malloc_nursery(24) # overflow - finish(p0, p1, p2) - ''' - self.interpret(ops, []) - # check the returned pointers - gc_ll_descr = self.cpu.gc_ll_descr - nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery) - ref = self.cpu.get_latest_value_ref - assert rffi.cast(lltype.Signed, ref(0)) == nurs_adr + 0 - assert rffi.cast(lltype.Signed, ref(1)) == nurs_adr + 16 - assert rffi.cast(lltype.Signed, ref(2)) == nurs_adr + 0 - # check the nursery content and state - gc_ll_descr.check_nothing_in_nursery() - assert gc_ll_descr.addrs[0] == nurs_adr + 24 - # this should call slow path once - assert gc_ll_descr.calls == [24] - -class MockShadowStackRootMap(MockGcRootMap): - is_shadow_stack = True - MARKER_FRAME = 88 # this marker follows the frame addr - S1 = lltype.GcStruct('S1') - - def __init__(self): - self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 20, - flavor='raw') - # root_stack_top - self.addrs[0] = rffi.cast(lltype.Signed, self.addrs) + 3*WORD - # random stuff - self.addrs[1] = 123456 - self.addrs[2] = 654321 - self.check_initial_and_final_state() - self.callshapes = {} - self.should_see = [] - - def check_initial_and_final_state(self): - assert self.addrs[0] == rffi.cast(lltype.Signed, self.addrs) + 3*WORD - assert self.addrs[1] == 123456 - assert self.addrs[2] == 654321 - - def get_root_stack_top_addr(self): - return rffi.cast(lltype.Signed, self.addrs) - - def compress_callshape(self, shape, datablockwrapper): - assert shape[0] == 'shape' - return ['compressed'] + shape[1:] - - def write_callshape(self, mark, force_index): - assert mark[0] == 'compressed' - assert force_index not in self.callshapes - assert force_index == 42 + len(self.callshapes) - self.callshapes[force_index] = mark - - def hook_malloc_slowpath(self): - num_entries = self.addrs[0] - rffi.cast(lltype.Signed, self.addrs) - assert num_entries == 5*WORD # 3 initially, plus 2 by the asm frame - assert self.addrs[1] == 123456 # unchanged - assert self.addrs[2] == 654321 # unchanged - frame_addr = self.addrs[3] # pushed by the asm frame - assert self.addrs[4] == self.MARKER_FRAME # pushed by the asm frame - # - from pypy.jit.backend.ppc.arch import FORCE_INDEX_OFS - addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), - frame_addr + FORCE_INDEX_OFS) - force_index = addr[0] - assert force_index == 43 # in this test: the 2nd call_malloc_nursery - # - # The callshapes[43] saved above should list addresses both in the - # COPY_AREA and in the "normal" stack, where all the 16 values p1-p16 - # of test_save_regs_at_correct_place should have been stored. Here - # we replace them with new addresses, to emulate a moving GC. - shape = self.callshapes[force_index] - assert len(shape[1:]) == len(self.should_see) - new_objects = [None] * len(self.should_see) - for ofs in shape[1:]: - assert isinstance(ofs, int) # not a register at all here - addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), frame_addr + ofs) - contains = addr[0] - for j in range(len(self.should_see)): - obj = self.should_see[j] - if contains == rffi.cast(lltype.Signed, obj): - assert new_objects[j] is None # duplicate? - break - else: - assert 0 # the value read from the stack looks random? - new_objects[j] = lltype.malloc(self.S1) - addr[0] = rffi.cast(lltype.Signed, new_objects[j]) - self.should_see[:] = new_objects - - -class TestMallocShadowStack(BaseTestRegalloc): - - def setup_method(self, method): - cpu = CPU(None, None) - cpu.gc_ll_descr = GCDescrFastpathMalloc() - cpu.gc_ll_descr.gcrootmap = MockShadowStackRootMap() - cpu.setup_once() - for i in range(42): - cpu.reserve_some_free_fail_descr_number() - self.cpu = cpu - - def test_save_regs_at_correct_place(self): - cpu = self.cpu - gc_ll_descr = cpu.gc_ll_descr - S1 = gc_ll_descr.gcrootmap.S1 - S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)), - ('s1', lltype.Ptr(S1)), - ('s2', lltype.Ptr(S1)), - ('s3', lltype.Ptr(S1)), - ('s4', lltype.Ptr(S1)), - ('s5', lltype.Ptr(S1)), - ('s6', lltype.Ptr(S1)), - ('s7', lltype.Ptr(S1)), - ('s8', lltype.Ptr(S1)), - ('s9', lltype.Ptr(S1)), - ('s10', lltype.Ptr(S1)), - ('s11', lltype.Ptr(S1)), - ('s12', lltype.Ptr(S1)), - ('s13', lltype.Ptr(S1)), - ('s14', lltype.Ptr(S1)), - ('s15', lltype.Ptr(S1)), - ('s16', lltype.Ptr(S1)), - ('s17', lltype.Ptr(S1)), - ('s18', lltype.Ptr(S1)), - ('s19', lltype.Ptr(S1)), - ('s20', lltype.Ptr(S1)), - ('s21', lltype.Ptr(S1)), - ('s22', lltype.Ptr(S1)), - ('s23', lltype.Ptr(S1)), - ('s24', lltype.Ptr(S1)), - ('s25', lltype.Ptr(S1)), - ('s26', lltype.Ptr(S1)), - ('s27', lltype.Ptr(S1))) - self.namespace = self.namespace.copy() - for i in range(28): - self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i) - ops = ''' - [p0] - p1 = getfield_gc(p0, descr=ds0) - p2 = getfield_gc(p0, descr=ds1) - p3 = getfield_gc(p0, descr=ds2) - p4 = getfield_gc(p0, descr=ds3) - p5 = getfield_gc(p0, descr=ds4) - p6 = getfield_gc(p0, descr=ds5) - p7 = getfield_gc(p0, descr=ds6) - p8 = getfield_gc(p0, descr=ds7) - p9 = getfield_gc(p0, descr=ds8) - p10 = getfield_gc(p0, descr=ds9) - p11 = getfield_gc(p0, descr=ds10) - p12 = getfield_gc(p0, descr=ds11) - p13 = getfield_gc(p0, descr=ds12) - p14 = getfield_gc(p0, descr=ds13) - p15 = getfield_gc(p0, descr=ds14) - p16 = getfield_gc(p0, descr=ds15) - p17 = getfield_gc(p0, descr=ds16) - p18 = getfield_gc(p0, descr=ds17) - p19 = getfield_gc(p0, descr=ds18) - p20 = getfield_gc(p0, descr=ds19) - p21 = getfield_gc(p0, descr=ds20) - p22 = getfield_gc(p0, descr=ds21) - p23 = getfield_gc(p0, descr=ds22) - p24 = getfield_gc(p0, descr=ds23) - p25 = getfield_gc(p0, descr=ds24) - p26 = getfield_gc(p0, descr=ds25) - p27 = getfield_gc(p0, descr=ds26) - p28 = getfield_gc(p0, descr=ds27) - # - # now all registers are in use - p29 = call_malloc_nursery(40) - p30 = call_malloc_nursery(40) # overflow - # - finish(p1, p2, p3, p4, p5, p6, p7, p8, \ - p9, p10, p11, p12, p13, p14, p15, p16, \ - p17, p18, p19, p20, p21, p22, p23, p24, \ - p25, p26, p27, p28) - ''' - s2 = lltype.malloc(S2) - for i in range(28): - s1 = lltype.malloc(S1) - setattr(s2, 's%d' % i, s1) - gc_ll_descr.gcrootmap.should_see.append(s1) - s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2) - # - self.interpret(ops, [s2ref]) - gc_ll_descr.check_nothing_in_nursery() - assert gc_ll_descr.calls == [40] - gc_ll_descr.gcrootmap.check_initial_and_final_state() - # check the returned pointers - for i in range(28): - s1ref = self.cpu.get_latest_value_ref(i) - s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref) - for j in range(28): - assert s1 != getattr(s2, 's%d' % j) - assert s1 == gc_ll_descr.gcrootmap.should_see[i] diff --git a/rpython/jit/backend/ppc/test/test_runner.py b/rpython/jit/backend/ppc/test/test_runner.py --- a/rpython/jit/backend/ppc/test/test_runner.py +++ b/rpython/jit/backend/ppc/test/test_runner.py @@ -22,18 +22,16 @@ # for the individual tests see # ====> ../../test/runner_test.py - if IS_PPC_32: - add_loop_instructions = ["ld", "add", "cmpwi", "beq", "b"] - else: - add_loop_instructions = ["ld", "add", "cmpdi", "beq", "b"] - bridge_loop_instructions = [ - "ld", "cmpdi", "bge+", - "li", "lis", "ori", "mtctr", "bctrl", - "lis", "ori", "mtctr", "bctr"] - bridge_loop_instructions_alternative = [ - "ld", "cmpdi", "bge+", - "li", "li", "rldicr", "oris", "ori", "mtctr", "bctrl", - "li", "rldicr", "oris", "ori", "mtctr", "bctr"] + assert not IS_PPC_32 + load_imm_instructions = ( + "(li|lis(; ori)?)(; rldicr(; oris)?(; ori)?)?") + add_loop_instructions = "ld; add; cmpdi; beq; b;$" + bridge_loop_instructions = ( + "ld; cmpdi; bge.; " + "li; %s; mtctr; %s; bctrl; " + "%s; mtctr; bctr;$" % ( + load_imm_instructions, load_imm_instructions, + load_imm_instructions)) def get_cpu(self): cpu = PPC_CPU(rtyper=None, stats=FakeStats()) diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -47,7 +47,6 @@ add_loop_instructions = ['overload for a specific cpu'] bridge_loop_instructions = ['overload for a specific cpu'] - bridge_loop_instructions_alternative = None # or another possible answer def execute_operation(self, opname, valueboxes, result_type, descr=None): inputargs, operations = self._get_single_operation_list(opname, @@ -4380,14 +4379,11 @@ # XXX we have to check the precise assembler, otherwise # we don't quite know if borders are correct - def checkops(mc, ops, alt_ops=None): - if len(mc) != len(ops) and alt_ops is not None: - ops = alt_ops - assert len(mc) == len(ops) - for i in range(len(mc)): - if ops[i] == '*': - continue # ingore ops marked as '*', i.e. inline constants - assert mc[i].split("\t")[2].startswith(ops[i]) + def checkops(mc, ops_regexp): + import re + words = [line.split("\t")[2].split()[0] + ';' for line in mc] + text = ' '.join(words) + assert re.compile(ops_regexp).match(text) data = ctypes.string_at(info.asmaddr, info.asmlen) try: @@ -4397,8 +4393,7 @@ data = ctypes.string_at(bridge_info.asmaddr, bridge_info.asmlen) mc = list(machine_code_dump(data, bridge_info.asmaddr, cpuname)) lines = [line for line in mc if line.count('\t') >= 2] - checkops(lines, self.bridge_loop_instructions, - self.bridge_loop_instructions_alternative) + checkops(lines, self.bridge_loop_instructions) except ObjdumpNotFound: py.test.skip("requires (g)objdump") diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -373,6 +373,14 @@ else: mc.MOV_rs(edi.value, WORD) else: + # This 'for_frame' version is called after a CALL. It does not + # need to save many registers: the registers that are anyway + # destroyed by the call can be ignored (volatiles), and the + # non-volatile registers won't be changed here. It only needs + # to save eax, maybe edx, and xmm0 (possible results of the call) + # and two more non-volatile registers (used to store the RPython + # exception that occurred in the CALL, if any). + assert not withcards # we have one word to align mc.SUB_ri(esp.value, 7 * WORD) # align and reserve some space mc.MOV_sr(WORD, eax.value) # save for later @@ -387,7 +395,7 @@ exc0, exc1 = ebx, r12 mc.MOV(RawEspLoc(WORD * 5, REF), exc0) mc.MOV(RawEspLoc(WORD * 6, INT), exc1) - # note that it's save to store the exception in register, + # note that it's safe to store the exception in register, # since the call to write barrier can't collect # (and this is assumed a bit left and right here, like lack # of _reload_frame_if_necessary) diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py --- a/rpython/jit/backend/x86/test/test_runner.py From noreply at buildbot.pypy.org Thu Sep 24 12:53:09 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 24 Sep 2015 12:53:09 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: only one test for llgraph failing Message-ID: <20150924105309.EF7691C139A@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79808:ed1cb45ccbd1 Date: 2015-09-24 12:53 +0200 http://bitbucket.org/pypy/pypy/changeset/ed1cb45ccbd1/ Log: only one test for llgraph failing 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 @@ -799,8 +799,8 @@ # vector operations vector_arith_code = """ - def bh_vec_{0}_{1}(self, vx, vy): - assert len(vx) == len(vy) + def bh_vec_{0}_{1}(self, vx, vy, count): + assert len(vx) == len(vy) == count return [_vx {2} _vy for _vx,_vy in zip(vx,vy)] """ exec py.code.Source(vector_arith_code.format('int','add','+')).compile() @@ -812,59 +812,66 @@ exec py.code.Source(vector_arith_code.format('float','truediv','/')).compile() exec py.code.Source(vector_arith_code.format('float','eq','==')).compile() - def bh_vec_float_neg(self, vx): + def bh_vec_float_neg(self, vx, count): return [e * -1 for e in vx] - def bh_vec_float_abs(self, vx): + def bh_vec_float_abs(self, vx, count): return [abs(e) for e in vx] - def bh_vec_float_eq(self, vx, vy): - assert len(vx) == len(vy) + def bh_vec_float_eq(self, vx, vy, count): + assert len(vx) == len(vy) == count return [_vx == _vy for _vx,_vy in zip(vx,vy)] - def bh_vec_float_ne(self, vx, vy): - assert len(vx) == len(vy) + def bh_vec_float_ne(self, vx, vy, count): + assert len(vx) == len(vy) == count return [_vx != _vy for _vx,_vy in zip(vx,vy)] bh_vec_int_eq = bh_vec_float_eq bh_vec_int_ne = bh_vec_float_ne - def bh_vec_int_xor(self, vx, vy): + def bh_vec_int_xor(self, vx, vy, count): return [int(x) ^ int(y) for x,y in zip(vx,vy)] - def bh_vec_float_pack(self, vector, value, index, count): - if isinstance(value, list): - for i in range(count): - vector[index + i] = value[i] - else: - vector[index] = value - return vector - - def bh_vec_cast_float_to_singlefloat(self, vx): + def bh_vec_cast_float_to_singlefloat(self, vx, count): return vx - def bh_vec_box(self, size): - return [0] * size + def bh_vec_f(self, count): + return [0.0] * count - def bh_vec_box_pack(self, vx, index, y): - vx[index] = y + def bh_vec_i(self, count): + return [0] * count - def bh_vec_box_unpack(self, vx, index): - return vx[index] + def _bh_vec_pack(self, tv, sv, index, count, _): + if not isinstance(sv, list): + tv[index] = sv + return tv + for i in range(count): + tv[index+i] = sv[i] + return tv - def bh_vec_float_expand(self, x, count): + bh_vec_pack_f = _bh_vec_pack + bh_vec_pack_i = _bh_vec_pack + + def _bh_vec_unpack(self, vx, index, count): + return vx[index:index+count] + + bh_vec_unpack_f = _bh_vec_unpack + bh_vec_unpack_i = _bh_vec_unpack + + def _bh_vec_expand(self, x, count): return [x] * count - def bh_vec_int_expand(self, x, count): - return [x] * count + bh_vec_expand_f = _bh_vec_expand + bh_vec_expand_i = _bh_vec_expand - def bh_vec_int_signext(self, vx, ext): + def bh_vec_int_signext(self, vx, ext, count): return [heaptracker.int_signext(_vx, ext) for _vx in vx] def build_getarrayitem(func): - def method(self, struct, offset, descr): + def method(self, struct, offset, descr, _count): values = [] count = self.vector_register_size // descr.get_item_size_in_bytes() + assert _count == count assert count > 0 for i in range(count): val = func(self, struct, offset + i, descr) @@ -878,10 +885,11 @@ bh_vec_getarrayitem_raw_f = build_getarrayitem(bh_getarrayitem_raw) del build_getarrayitem - def _bh_vec_raw_load(self, struct, offset, descr): + def _bh_vec_raw_load(self, struct, offset, descr, _count): values = [] stride = descr.get_item_size_in_bytes() count = self.vector_register_size // descr.get_item_size_in_bytes() + assert _count == count assert count > 0 for i in range(count): val = self.bh_raw_load(struct, offset + i*stride, descr) @@ -891,16 +899,16 @@ bh_vec_raw_load_i = _bh_vec_raw_load bh_vec_raw_load_f = _bh_vec_raw_load - def bh_vec_raw_store(self, struct, offset, newvalues, descr): + def bh_vec_raw_store(self, struct, offset, newvalues, descr, count): stride = descr.get_item_size_in_bytes() for i,n in enumerate(newvalues): self.bh_raw_store(struct, offset + i*stride, n, descr) - def bh_vec_setarrayitem_raw(self, struct, offset, newvalues, descr): + def bh_vec_setarrayitem_raw(self, struct, offset, newvalues, descr, count): for i,n in enumerate(newvalues): self.bh_setarrayitem_raw(struct, offset + i, n, descr) - def bh_vec_setarrayitem_gc(self, struct, offset, newvalues, descr): + def bh_vec_setarrayitem_gc(self, struct, offset, newvalues, descr, count): for i,n in enumerate(newvalues): self.bh_setarrayitem_gc(struct, offset + i, n, descr) @@ -1026,9 +1034,9 @@ i = accuminfo.getpos_in_failargs() value = values[i] assert isinstance(value, list) - if accum.operator == '+': + if accuminfo.accum_operation == '+': value = sum(value) - elif accum.operator == '*': + elif accuminfo.accum_operation == '*': def prod(acc, x): return acc * x value = reduce(prod, value, 1) else: @@ -1404,6 +1412,10 @@ new_args = args + (descr,) else: new_args = args + if opname.startswith('vec_'): + count = self.current_op.count + assert count > 1 + new_args = new_args + (count,) return getattr(self.cpu, 'bh_' + opname)(*new_args) execute.func_name = 'execute_' + opname return execute diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -134,6 +134,9 @@ return str(arg.getfloatstorage()) elif arg is None: return 'None' + elif arg.is_vector(): + suffix = '[%dx%s%d]' % (arg.count, arg.datatype, arg.bytesize * 8) + return 'v' + str(mv) + suffix elif arg.type == 'i': return 'i' + str(mv) elif arg.type == 'r': diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -149,10 +149,6 @@ assert operations[self.index] is self.op operations[self.index] = None descr = self.op.getdescr() - # TODO loop.version_info.remove(descr) - #if descr and descr.loop_version(): - # assert isinstance(descr, CompileLoopVersionDescr) - # descr.version = None if operations[self.index-1] is self.cmp_op: operations[self.index-1] = None diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -28,12 +28,18 @@ loop.operations = self.oplist loop.prefix = self.invariant_oplist if len(self.invariant_vector_vars) + len(self.invariant_oplist) > 0: + # label args = loop.label.getarglist_copy() + self.invariant_vector_vars opnum = loop.label.getopnum() - # TODO descr? op = loop.label.copy_and_change(opnum, args) self.renamer.rename(op) loop.prefix_label = op + # jump + args = loop.jump.getarglist_copy() + self.invariant_vector_vars + opnum = loop.jump.getopnum() + op = loop.jump.copy_and_change(opnum, args) + self.renamer.rename(op) + loop.jump = op def profitable(self): return True @@ -56,9 +62,11 @@ def ensure_args_unpacked(self, op): pass - def post_emit(self, op): + def post_emit(self, node): pass + def pre_emit(self, node): + pass class Scheduler(object): """ Create an instance of this class to (re)schedule a vector trace. """ @@ -123,7 +131,7 @@ state.renamer.rename(op) if unpack: state.ensure_args_unpacked(op) - state.post_emit(node.getoperation()) + state.post_emit(node) def walk_and_emit(self, state): """ Emit all the operations into the oplist parameter. @@ -134,6 +142,7 @@ if node: if not state.emit(node, self): if not node.emitted: + state.pre_emit(node) self.mark_emitted(node, state) if not node.is_imaginary(): op = node.getoperation() @@ -259,6 +268,8 @@ for i,node in enumerate(pack.operations): op = node.getoperation() state.setvector_of_box(op,i,vecop) + if pack.is_accumulating(): + state.renamer.start_renaming(op, vecop) if op.is_guard(): assert isinstance(op, GuardResOp) assert isinstance(vecop, GuardResOp) @@ -452,7 +463,8 @@ args[index] = vecop return vecop - vecop = OpHelpers.create_vec(arg.type, arg.bytesize, arg.signed) + + vecop = OpHelpers.create_vec(arg.type, arg.bytesize, arg.signed, pack.opnum()) ops.append(vecop) for i,node in enumerate(pack.operations): op = node.getoperation() @@ -519,7 +531,11 @@ return vecop return None - def post_emit(self, op): + def post_emit(self, node): + pass + + def pre_emit(self, node): + op = node.getoperation() if op.is_guard(): # add accumulation info to the descriptor # TODO for version in self.loop.versions: @@ -536,8 +552,9 @@ accum = self.accumulation.get(arg, None) if accum: assert isinstance(accum, AccumPack) - accum.attach_accum_info(descr, i, arg) - seed = accum.getseed() + descr.rd_accum_list = AccumInfo(descr.rd_accum_list, i, + accum.operator, arg, None) + seed = accum.getleftmostseed() failargs[i] = self.renamer.rename_map.get(seed, seed) def profitable(self): @@ -556,6 +573,7 @@ if node.pack: assert node.pack.numops() > 1 for node in node.pack.operations: + self.pre_emit(node) scheduler.mark_emitted(node, self, unpack=False) turn_into_vector(self, node.pack) return True @@ -593,6 +611,7 @@ if argument and not argument.is_constant(): arg = self.ensure_unpacked(i, argument) if argument is not arg: + print "exchange at", i, fail_args[i], "=", arg fail_args[i] = arg def ensure_unpacked(self, index, arg): @@ -603,7 +622,7 @@ if var in self.invariant_vector_vars: return arg if arg in self.accumulation: - return var + return arg args = [var, ConstInt(pos), ConstInt(1)] vecop = OpHelpers.create_vec_unpack(var.type, args, var.bytesize, var.signed, 1) @@ -844,35 +863,34 @@ rop.FLOAT_MUL: '*', } - def __init__(self, nodes, operator, accum, position): + def __init__(self, nodes, operator, position): Pack.__init__(self, nodes) - self.accumulator = accum self.operator = operator self.position = position def getdatatype(self): - return self.accumulator.datatype + accum = self.leftmost().getarg(self.position) + return accum.datatype def getbytesize(self): - return self.accumulator.bytesize + accum = self.leftmost().getarg(self.position) + return accum.bytesize - def getseed(self): + def getleftmostseed(self): + return self.leftmost().getarg(self.position) + + def getseeds(self): """ The accumulatoriable holding the seed value """ - return self.accumulator + return [op.getoperation().getarg(self.position) for op in self.operations] def reduce_init(self): if self.operator == '*': return 1 return 0 - def attach_accum_info(self, descr, position, scalar): - descr.rd_accum_list = AccumInfo(descr.rd_accum_list, position, self.operator, - scalar, None) - def is_accumulating(self): return True def clone(self): - return AccumPack(operations, self.operator, - self.accumulator, self.position) + return AccumPack(operations, self.operator, self.position) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -81,11 +81,11 @@ def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ user_code = not jitdriver_sd.vec and warmstate.vec_all + loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) if user_code and user_loop_bail_fast_path(loop, warmstate): return # the original loop (output of optimize_unroll) info = LoopVersionInfo(loop_info) - loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) version = info.snapshot(loop) try: debug_start("vec-opt-loop") @@ -134,7 +134,6 @@ resop_count = 0 # the count of operations minus debug_merge_points vector_instr = 0 guard_count = 0 - blacklist = (rop.CALL, rop.CALL_ASSEMBLER) at_least_one_array_access = True for i,op in enumerate(loop.operations): if op.getopnum() == rop.DEBUG_MERGE_POINT: @@ -149,7 +148,8 @@ at_least_one_array_access = True if warmstate.vec_ratio > 0.0: - if op.getopnum() in blacklist: + # blacklist + if op.is_call() or op.is_call_assembler(): return True if op.is_guard(): @@ -744,7 +744,7 @@ # considered. => tree pattern matching problem. return None operator = AccumPack.SUPPORTED[opnum] - return AccumPack([lnode, rnode], operator, scalar, index) + return AccumPack([lnode, rnode], operator, index) return None @@ -770,7 +770,7 @@ oplist = state.invariant_oplist # reset the box to zeros or ones if pack.reduce_init() == 0: - vecop = OpHelpers.create_vec(datatype, bytesize, signed) + vecop = OpHelpers.create_vec(datatype, bytesize, signed, count) oplist.append(vecop) vecop = VecOperation(rop.VEC_INT_XOR, [vecop, vecop], vecop, count) @@ -783,14 +783,15 @@ else: raise NotImplementedError("cannot handle %s" % pack.operator) # pack the scalar value - args = [vecop, pack.getseed(), ConstInt(0), ConstInt(1)] + args = [vecop, pack.getleftmostseed(), ConstInt(0), ConstInt(1)] vecop = OpHelpers.create_vec_pack(datatype, args, bytesize, signed, count) oplist.append(vecop) + seed = pack.getleftmostseed() + state.accumulation[seed] = pack # rename the variable with the box - state.setvector_of_box(pack.getseed(), 0, vecop) # prevent it from expansion - state.renamer.start_renaming(pack.getseed(), vecop) - + state.setvector_of_box(seed, 0, vecop) # prevent it from expansion + state.renamer.start_renaming(seed, vecop) def split_overloaded_packs(self): newpacks = [] diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -146,6 +146,10 @@ else: # pass through the type of the first input argument if self.numargs() == 0: + if self.type == 'i': + self.setdatatype('i', INT_WORD, True) + elif self.type == 'f': + self.setdatatype('f', FLOAT_WORD, False) return i = 0 arg = self.getarg(i) @@ -280,6 +284,9 @@ if descr is DONT_CHANGE: descr = None newop = ResOperation(opnum, args, descr) + newop.count = self.count + newop.bytesize = self.bytesize + newop.signed = self.signed if self.type != 'v': newop.copy_value_from(self) return newop @@ -1602,13 +1609,13 @@ return VecOperationNew(opnum, [arg], arg.type, bytesize, signed, count) @staticmethod - def create_vec(datatype, bytesize, signed): + def create_vec(datatype, bytesize, signed, count): if datatype == 'i': opnum = rop.VEC_I else: assert datatype == 'f' opnum = rop.VEC_F - return VecOperationNew(opnum, [], datatype, bytesize, signed, 0) + return VecOperationNew(opnum, [], datatype, bytesize, signed, count) @staticmethod def create_vec_pack(datatype, args, bytesize, signed, count): From noreply at buildbot.pypy.org Thu Sep 24 14:46:39 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 14:46:39 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move: A branch to fix issue #2141: after the fix for issue #2017, one good Message-ID: <20150924124639.A382B1C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move Changeset: r79809:4ef6c875023c Date: 2015-09-24 14:46 +0200 http://bitbucket.org/pypy/pypy/changeset/4ef6c875023c/ Log: A branch to fix issue #2141: after the fix for issue #2017, one good optimization in the JIT doesn't actually work if we are running more than MAX threads (20). I will try to revert that patch and fix it differently inside stacklet.c directly. From noreply at buildbot.pypy.org Thu Sep 24 15:34:12 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 24 Sep 2015 15:34:12 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: llgraph working again Message-ID: <20150924133412.3362E1C1455@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79810:f1468a7d8892 Date: 2015-09-24 15:34 +0200 http://bitbucket.org/pypy/pypy/changeset/f1468a7d8892/ Log: llgraph working again diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -87,6 +87,7 @@ # guard descr = CompileLoopVersionDescr() descr.copy_all_attributes_from(self.op.getdescr()) + descr.rd_accum_list = None # do not copy the accum list assert isinstance(descr, ResumeGuardDescr) guard = ResOperation(self.op.getopnum(), [compare], descr=descr) guard.setfailargs(loop.label.getarglist_copy()) @@ -318,14 +319,5 @@ info.track(transitive_guard, descr, version) info.clear() - loop.prefix += self._newoperations + loop.prefix = self._newoperations + loop.prefix loop.operations = [op for op in loop.operations if op] - - # TODO if self.has_two_labels: - # TODO oplist = [loop.operations[0]] + self._newoperations + \ - # TODO [op for op in loop.operations[1:] if op] - # TODO loop.operations = oplist - # TODO else: - # TODO loop.operations = self._newoperations + \ - # TODO [op for op in loop.operations if op] - diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -555,7 +555,9 @@ descr.rd_accum_list = AccumInfo(descr.rd_accum_list, i, accum.operator, arg, None) seed = accum.getleftmostseed() + print "pre", failargs[i], "=>", failargs[i] = self.renamer.rename_map.get(seed, seed) + print failargs[i] def profitable(self): return self.costmodel.profitable() diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -66,8 +66,20 @@ return oplist + self.operations + [self.jump] def clone(self): + renamer = Renamer() + label = self.label.copy() + prefix = [] + for op in self.prefix: + newop = op.copy() + renamer.rename(newop) + if not newop.returns_void(): + renamer.start_renaming(op, newop) + prefix.append(newop) + prefix_label = None + if self.prefix_label: + prefix_label = self.prefix_label.copy() + renamer.rename(prefix_label) oplist = [] - renamer = Renamer() for op in self.operations: newop = op.copy() renamer.rename(newop) @@ -76,7 +88,10 @@ oplist.append(newop) jump = self.jump.copy() renamer.rename(jump) - return VectorLoop(self.label.copy(), oplist, jump) + loop = VectorLoop(self.label.copy(), oplist, jump) + loop.prefix = prefix + loop.prefix_label = prefix_label + return loop def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -270,6 +270,10 @@ # -------------- def copy(self): + if self.is_guard(): + op = self.copy_and_change(self.opnum) + op.setfailargs(self.getfailargs()[:]) + return op return self.copy_and_change(self.opnum) def copy_and_change(self, opnum, args=None, descr=None): From noreply at buildbot.pypy.org Thu Sep 24 17:06:41 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 17:06:41 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move: Implement shadow stack support directly inside the stacklet code Message-ID: <20150924150642.046EF1C1277@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move Changeset: r79811:75c41a62a963 Date: 2015-09-24 17:06 +0200 http://bitbucket.org/pypy/pypy/changeset/75c41a62a963/ Log: Implement shadow stack support directly inside the stacklet code diff --git a/rpython/translator/c/src/stacklet/stacklet.c b/rpython/translator/c/src/stacklet/stacklet.c --- a/rpython/translator/c/src/stacklet/stacklet.c +++ b/rpython/translator/c/src/stacklet/stacklet.c @@ -34,15 +34,19 @@ /************************************************************/ struct stacklet_s { - /* The portion of the real stack claimed by this paused tealet. */ + /* The portion of the real stack claimed by this paused stacklet. */ char *stack_start; /* the "near" end of the stack */ char *stack_stop; /* the "far" end of the stack */ + char *shadow_stack_start; /* the "near" end of the shadow stack */ + char *shadow_stack_stop; /* the "far" end of the shadow stack */ + /* The amount that has been saved away so far, just after this struct. * There is enough allocated space for 'stack_stop - stack_start' * bytes. */ ptrdiff_t stack_saved; /* the amount saved */ + ptrdiff_t shadow_stack_saved; /* Internally, some stacklets are arranged in a list, to handle lazy * saving of stacks: if the stacklet has a partially unsaved stack, @@ -65,13 +69,16 @@ struct stacklet_s *g_stack_chain_head; /* NULL <=> running main */ char *g_current_stack_stop; char *g_current_stack_marker; + char *g_current_shadow_stack_stop; /* oldest, i.e. smallest address */ + char *g_current_shadow_stack_marker; struct stacklet_s *g_source; struct stacklet_s *g_target; + char **g_shadow_stack_ref; }; /***************************************************************/ -static void g_save(struct stacklet_s* g, char* stop +static void g_save(struct stacklet_s* g, char* stop, char *shadow_stop #ifdef DEBUG_DUMP , int overwrite_stack_for_debug #endif @@ -93,10 +100,12 @@ | | |xxxxxxx| g->stack_start | | |_______| g+1 + ("g+1" because it is immediately after the struct "*g" in memory) */ ptrdiff_t sz1 = g->stack_saved; ptrdiff_t sz2 = stop - g->stack_start; assert(stop <= g->stack_stop); + /* i.e. sz2 <= g->stack_stop - g->stack_start */ if (sz2 > sz1) { char *c = (char *)(g + 1); @@ -111,6 +120,31 @@ #endif g->stack_saved = sz2; } + + /* Shadow stack: very similar code, but in the opposite order. + The shadow stack grows towards higher addresses. + + g->shadow_stack_start _______ end + | | |xxxxxxx| + | | |xxxxxxx| + |________| |_______| + |xxxxxxxx| ==> : : + |xxx __ stop ......... + |xxxxxxxx| + g->shadow_stack_stop |________| + */ + sz1 = g->shadow_stack_saved; + sz2 = g->shadow_stack_start - shadow_stop; + assert(shadow_stop >= g->shadow_stack_stop); + /* i.e. sz2 <= g->shadow_stack_start - g->shadow_stack_stop */ + + if (sz2 > sz1) { + char *end = ((char *)(g + 1)) + + (g->stack_stop - g->stack_start) + + (g->shadow_stack_start - g->shadow_stack_stop); + memcpy(end - sz2, shadow_stop, sz2 - sz1); + g->shadow_stack_saved = sz2; + } } /* Allocate and store in 'g_source' a new stacklet, which has the C @@ -124,6 +158,10 @@ struct stacklet_s *stacklet; ptrdiff_t stack_size = (thrd->g_current_stack_stop - (char *)old_stack_pointer); + if (thrd->g_shadow_stack_ref != NULL) { + stack_size += (*thrd->g_shadow_stack_ref - + thrd->g_current_shadow_stack_stop); + } thrd->g_source = malloc(sizeof(struct stacklet_s) + stack_size); if (thrd->g_source == NULL) @@ -133,6 +171,15 @@ stacklet->stack_start = old_stack_pointer; stacklet->stack_stop = thrd->g_current_stack_stop; stacklet->stack_saved = 0; + if (thrd->g_shadow_stack_ref != NULL) { + stacklet->shadow_stack_start = *thrd->g_shadow_stack_ref; + stacklet->shadow_stack_stop = thrd->g_current_shadow_stack_stop; + } + else { + stacklet->shadow_stack_start = NULL; + stacklet->shadow_stack_stop = NULL; + } + stacklet->shadow_stack_saved = 0; stacklet->stack_prev = thrd->g_stack_chain_head; stacklet->stack_thrd = thrd; thrd->g_stack_chain_head = stacklet; @@ -140,14 +187,18 @@ } /* Save more of the C stack away, up to 'target_stop'. + + Note that this is driven by the C stack; it is assumed that the + shadowstack cannot grow without the C stack also growing. */ static void g_clear_stack(struct stacklet_s *g_target, struct stacklet_thread_s *thrd) { struct stacklet_s *current = thrd->g_stack_chain_head; char *target_stop = g_target->stack_stop; + char *shadow_target_stop = g_target->shadow_stack_stop; - /* save and unlink tealets that are completely within + /* save and unlink stacklets that are completely within the area to clear. */ while (current != NULL && current->stack_stop <= target_stop) { struct stacklet_s *prev = current->stack_prev; @@ -155,7 +206,7 @@ if (current != g_target) { /* don't bother saving away g_target, because it would be immediately restored */ - g_save(current, current->stack_stop + g_save(current, current->stack_stop, current->shadow_stack_stop #ifdef DEBUG_DUMP , 1 #endif @@ -166,7 +217,7 @@ /* save a partial stack */ if (current != NULL && current->stack_start < target_stop) - g_save(current, target_stop + g_save(current, target_stop, shadow_target_stop #ifdef DEBUG_DUMP , 1 #endif @@ -185,6 +236,8 @@ if (g_allocate_source_stacklet(old_stack_pointer, thrd) < 0) return NULL; g_clear_stack(thrd->g_target, thrd); + if (thrd->g_shadow_stack_ref != NULL) + *thrd->g_shadow_stack_ref = thrd->g_target->shadow_stack_start; return thrd->g_target->stack_start; } @@ -195,7 +248,8 @@ { struct stacklet_thread_s *thrd = (struct stacklet_thread_s *)rawthrd; if (g_allocate_source_stacklet(old_stack_pointer, thrd) == 0) - g_save(thrd->g_source, thrd->g_current_stack_marker + g_save(thrd->g_source, thrd->g_current_stack_marker, + thrd->g_current_shadow_stack_marker #ifdef DEBUG_DUMP , 0 #endif @@ -210,6 +264,8 @@ struct stacklet_thread_s *thrd = (struct stacklet_thread_s *)rawthrd; thrd->g_source = EMPTY_STACKLET_HANDLE; g_clear_stack(thrd->g_target, thrd); + if (thrd->g_shadow_stack_ref != NULL) + *thrd->g_shadow_stack_ref = thrd->g_target->shadow_stack_start; return thrd->g_target->stack_start; } @@ -222,6 +278,7 @@ struct stacklet_thread_s *thrd = (struct stacklet_thread_s *)rawthrd; struct stacklet_s *g = thrd->g_target; ptrdiff_t stack_saved = g->stack_saved; + ptrdiff_t shadow_stack_saved; assert(new_stack_pointer == g->stack_start); #if STACK_DIRECTION == 0 @@ -229,7 +286,20 @@ #else memcpy(g->stack_start - stack_saved, g+1, stack_saved); #endif + + shadow_stack_saved = g->shadow_stack_saved; + if (shadow_stack_saved > 0) { + char *end = ((char *)(g + 1)) + + (g->stack_stop - g->stack_start) + + (g->shadow_stack_start - g->shadow_stack_stop); + memcpy(g->shadow_stack_start - shadow_stack_saved, + end - shadow_stack_saved, + shadow_stack_saved); + } + thrd->g_current_stack_stop = g->stack_stop; + thrd->g_current_shadow_stack_stop = g->shadow_stack_stop; + free(g); return EMPTY_STACKLET_HANDLE; } @@ -247,6 +317,7 @@ /* First time it returns. Only g_initial_save_state() has run and has created 'g_source'. Call run(). */ thrd->g_current_stack_stop = thrd->g_current_stack_marker; + thrd->g_current_shadow_stack_stop = thrd->g_current_shadow_stack_marker; result = run(thrd->g_source, run_arg); /* Then switch to 'result'. */ @@ -261,7 +332,7 @@ /************************************************************/ -stacklet_thread_handle stacklet_newthread(void) +stacklet_thread_handle stacklet_newthread_shadowstack(void **shadow_stack_ref) { struct stacklet_thread_s *thrd; @@ -273,11 +344,18 @@ } thrd = malloc(sizeof(struct stacklet_thread_s)); - if (thrd != NULL) + if (thrd != NULL) { memset(thrd, 0, sizeof(struct stacklet_thread_s)); + thrd->g_shadow_stack_ref = (char **)shadow_stack_ref; + } return thrd; } +stacklet_thread_handle stacklet_newthread(void) +{ + return stacklet_newthread_shadowstack(NULL); +} + void stacklet_deletethread(stacklet_thread_handle thrd) { free(thrd); @@ -292,6 +370,16 @@ thrd->g_current_stack_stop = ((char *)&stackmarker) + 1; thrd->g_current_stack_marker = (char *)&stackmarker; + + if (thrd->g_shadow_stack_ref != NULL) { + char *shadowstackmarker = *thrd->g_shadow_stack_ref; + assert(shadowstackmarker != NULL); + if (thrd->g_current_shadow_stack_stop == NULL || + thrd->g_current_shadow_stack_stop > shadowstackmarker) + thrd->g_current_shadow_stack_stop = shadowstackmarker; + thrd->g_current_shadow_stack_marker = shadowstackmarker; + } + _stacklet_initialstub(thrd, run, run_arg); return thrd->g_source; } @@ -303,6 +391,14 @@ if (thrd->g_current_stack_stop <= (char *)&stackmarker) thrd->g_current_stack_stop = ((char *)&stackmarker) + 1; + if (thrd->g_shadow_stack_ref != NULL) { + char *shadowstackmarker = *thrd->g_shadow_stack_ref; + assert(shadowstackmarker != NULL); + assert(thrd->g_current_shadow_stack_stop != NULL); + if (thrd->g_current_shadow_stack_stop > shadowstackmarker) + thrd->g_current_shadow_stack_stop = shadowstackmarker; + } + thrd->g_target = target; _stacklet_switchstack(g_save_state, g_restore_state, thrd); return thrd->g_source; @@ -350,3 +446,29 @@ } return ptr; } + +char **_stacklet_translate_shadow_pointer(stacklet_handle context, char **ptr) +{ + char *p = (char *)ptr; + long delta; + if (context == NULL) + return ptr; + delta = context->shadow_stack_start - p; + if (((unsigned long)(delta - 1)) < + ((unsigned long)context->shadow_stack_saved)) { + /* a pointer to a saved away word */ + char *end = ((char *)(context + 1)) + + (context->stack_stop - context->stack_start) + + (context->shadow_stack_start - context->shadow_stack_stop); + return (char **)(end - delta); + } + if (((unsigned long)delta) > (unsigned long)(context->shadow_stack_start - + context->shadow_stack_stop)) { + /* out-of-stack pointer! it's only ok if we are the main stacklet + and we are reading past the end, because the main stacklet's + stack stop is not exactly known. */ + assert(delta >= 0); + assert(((long)context->stack_stop) & 1); + } + return ptr; +} diff --git a/rpython/translator/c/src/stacklet/stacklet.h b/rpython/translator/c/src/stacklet/stacklet.h --- a/rpython/translator/c/src/stacklet/stacklet.h +++ b/rpython/translator/c/src/stacklet/stacklet.h @@ -19,10 +19,20 @@ /* Multithread support. + + Shadowstack support: if the rest of the program manages some + "shadowstack" data, which grows and shrinks in parallel with the C + stack, then it needs support here to save and restore parts of it + in parallel to the real stack. To do that, pass in the arguments + called "shadow_stack_ref" a pointer to the current shadowstack + pointer. It is assumed to grow towards higher addresses. Pass NULL + if you don't need this. */ typedef struct stacklet_thread_s *stacklet_thread_handle; RPY_EXTERN stacklet_thread_handle stacklet_newthread(void); +RPY_EXTERN stacklet_thread_handle stacklet_newthread_shadowstack( + void **shadow_stack_ref); RPY_EXTERN void stacklet_deletethread(stacklet_thread_handle thrd); @@ -59,5 +69,7 @@ */ RPY_EXTERN char **_stacklet_translate_pointer(stacklet_handle context, char **ptr); +RPY_EXTERN +char **_stacklet_translate_shadow_pointer(stacklet_handle context, char **ptr); #endif /* _STACKLET_H_ */ diff --git a/rpython/translator/c/src/stacklet/tests.c b/rpython/translator/c/src/stacklet/tests.c --- a/rpython/translator/c/src/stacklet/tests.c +++ b/rpython/translator/c/src/stacklet/tests.c @@ -625,6 +625,126 @@ tealet_delete(g_sub2); } #endif + +static long my_shadowstack[10]; +static long *shadowstack_top = my_shadowstack; + +static void trash_more_shadowstack(void) +{ + *shadowstack_top++ = 42; + *shadowstack_top++ = 43; + *shadowstack_top++ = 44; + shadowstack_top -= 3; +} + +stacklet_handle switchbackonce_callback_shadow_1(stacklet_handle h, void *arg) +{ + assert(arg == (void *)123); + assert(status == 0); + status = 1; + assert(h != EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack + 1); + *shadowstack_top++ = 1001; + *shadowstack_top++ = 1002; + trash_more_shadowstack(); + + h = stacklet_switch(h); + assert(status == 4); + assert(h != EMPTY_STACKLET_HANDLE); + status = 5; + + assert(shadowstack_top == my_shadowstack + 3); + assert(my_shadowstack[1] == 1001); + assert(my_shadowstack[2] == 1002); + trash_more_shadowstack(); + shadowstack_top -= 2; + + return h; +} + +stacklet_handle switchbackonce_callback_shadow_2(stacklet_handle h, void *arg) +{ + assert(arg == (void *)456); + assert(status == 2); + status = 3; + assert(h != EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack + 2); + *shadowstack_top++ = 2002; + *shadowstack_top++ = 2003; + trash_more_shadowstack(); + + h = stacklet_switch(h); + assert(status == 5); + assert(h != EMPTY_STACKLET_HANDLE); + status = 6; + + assert(shadowstack_top == my_shadowstack + 4); + assert(my_shadowstack[2] == 2002); + assert(my_shadowstack[3] == 2003); + trash_more_shadowstack(); + shadowstack_top -= 2; + + return h; +} + +void test_shadowstack(void) +{ + status = 0; + shadowstack_top = my_shadowstack; + *shadowstack_top++ = 500; + trash_more_shadowstack(); + + stacklet_handle h = stacklet_new(thrd, switchbackonce_callback_shadow_1, + (void *)123); + assert(h != EMPTY_STACKLET_HANDLE); + assert(status == 1); + status = 2; + + assert(shadowstack_top == my_shadowstack + 1); + assert(my_shadowstack[0] == 500); + *shadowstack_top++ = 501; + trash_more_shadowstack(); + + stacklet_handle h2 = stacklet_new(thrd, switchbackonce_callback_shadow_2, + (void *)456); + assert(h2 != EMPTY_STACKLET_HANDLE); + assert(status == 3); + status = 4; + + assert(shadowstack_top == my_shadowstack + 2); + assert(my_shadowstack[0] == 500); + assert(my_shadowstack[1] == 501); + *shadowstack_top++ = 502; + *shadowstack_top++ = 503; + trash_more_shadowstack(); + + h = stacklet_switch(h); + assert(status == 5); + assert(h == EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack + 4); + assert(my_shadowstack[0] == 500); + assert(my_shadowstack[1] == 501); + assert(my_shadowstack[2] == 502); + assert(my_shadowstack[3] == 503); + *shadowstack_top++ = 504; + trash_more_shadowstack(); + + h2 = stacklet_switch(h2); + assert(status == 6); + assert(h2 == EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack + 5); + assert(my_shadowstack[0] == 500); + assert(my_shadowstack[1] == 501); + assert(my_shadowstack[2] == 502); + assert(my_shadowstack[3] == 503); + assert(my_shadowstack[4] == 504); + shadowstack_top -= 5; +} + /************************************************************/ #define TEST(name) { name, #name } @@ -649,6 +769,7 @@ TEST(test_double), TEST(test_random), #endif + TEST(test_shadowstack), { NULL, NULL } }; @@ -659,7 +780,7 @@ if (argc > 1) srand(atoi(argv[1])); - thrd = stacklet_newthread(); + thrd = stacklet_newthread_shadowstack((void **)&shadowstack_top); for (tst=test_list; tst->runtest; tst++) { printf("+++ Running %s... +++\n", tst->name); From noreply at buildbot.pypy.org Thu Sep 24 17:50:56 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 24 Sep 2015 17:50:56 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: x86 assembler half way through, accumulation leaves behind an fail descr that is tried to be stiched (but removed from the trace) Message-ID: <20150924155056.2C2071C06AD@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79812:fd39e085206b Date: 2015-09-24 17:50 +0200 http://bitbucket.org/pypy/pypy/changeset/fd39e085206b/ Log: x86 assembler half way through, accumulation leaves behind an fail descr that is tried to be stiched (but removed from the trace) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1787,8 +1787,7 @@ self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) - def genop_guard_guard_nonnull_class(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_nonnull_class(self, guard_op, guard_token, locs, ign): self.mc.CMP(locs[0], imm1) # Patched below self.mc.J_il8(rx86.Conditions['B'], 0) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -63,8 +63,7 @@ save_around_call_regs = [eax, ecx, edx, esi, edi, r8, r9, r10] class X86XMMRegisterManager(RegisterManager): - - box_types = [FLOAT, VECTOR] + box_types = [FLOAT, INT] # yes INT! all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] # we never need lower byte I hope save_around_call_regs = all_regs @@ -203,7 +202,7 @@ return self.fm.get_frame_depth() def possibly_free_var(self, var): - if var.type == FLOAT or var.type == VECTOR: + if var.type == FLOAT or var.is_vector(): self.xrm.possibly_free_var(var) else: self.rm.possibly_free_var(var) @@ -223,7 +222,7 @@ def make_sure_var_in_reg(self, var, forbidden_vars=[], selected_reg=None, need_lower_byte=False): - if var.type == FLOAT or var.type == VECTOR: + if var.type == FLOAT or var.is_vector(): if isinstance(var, ConstFloat): return FloatImmedLoc(var.getfloatstorage()) return self.xrm.make_sure_var_in_reg(var, forbidden_vars, @@ -234,7 +233,7 @@ def force_allocate_reg(self, var, forbidden_vars=[], selected_reg=None, need_lower_byte=False): - if var.type == FLOAT or var.type == VECTOR: + if var.type == FLOAT or var.is_vector(): return self.xrm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) else: @@ -317,26 +316,15 @@ self.assembler.regalloc_perform_math(op, arglocs, result_loc) def locs_for_fail(self, guard_op): - faillocs = [] + faillocs = [self.loc(arg) for arg in guard_op.getfailargs()] descr = guard_op.getdescr() - for i,arg in enumerate(guard_op.getfailargs()): - if arg is None: - faillocs.append(None) - continue - if arg.is_vector() and arg.getaccum(): - # for an accumulator store the position of the original - # box and in llsupport/assembler save restore information - # on the descriptor - loc = self.loc(accum.getoriginalbox()) - faillocs.append(loc) - assert isinstance(descr, ResumeGuardDescr) - descr.rd_accum_list = AccumInfo(descr.rd_accum_list, - i, accum.operator, - accum.getoriginalbox(), - self.loc(arg)) - else: - faillocs.append(self.loc(arg)) - + if descr and descr.rd_accum_list: + accuminfo = descr.rd_accum_list + while accuminfo: + accuminfo.vector_loc = faillocs[accuminfo.getpos_in_failargs()] + loc = self.loc(accuminfo.getoriginal()) + faillocs[accuminfo.getpos_in_failargs()] = loc + accuminfo = accuminfo.next() return faillocs def perform_guard(self, guard_op, arglocs, result_loc): @@ -406,7 +394,7 @@ def loc(self, v): if v is None: # xxx kludgy return None - if v.type == FLOAT or v.type == VECTOR: + if v.type == FLOAT or v.is_vector(): return self.xrm.loc(v) return self.rm.loc(v) @@ -1392,7 +1380,7 @@ box = op.getarg(i) src_loc = self.loc(box) dst_loc = arglocs[i] - if box.type != FLOAT and box.type != VECTOR: + if box.type != FLOAT and not box.is_vector(): src_locations1.append(src_loc) dst_locations1.append(dst_loc) else: diff --git a/rpython/jit/backend/x86/test/test_x86vector.py b/rpython/jit/backend/x86/test/test_x86vector.py --- a/rpython/jit/backend/x86/test/test_x86vector.py +++ b/rpython/jit/backend/x86/test/test_x86vector.py @@ -14,9 +14,18 @@ class TestBasic(test_basic.Jit386Mixin, test_vector.VectorizeTests): # for the individual tests see # ====> ../../../metainterp/test/test_basic.py + def setup_method(self, method): + clazz = self.CPUClass + def init(*args, **kwargs): + cpu = clazz(*args, **kwargs) + cpu.supports_guard_gc_type = True + return cpu + self.CPUClass = init + enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' class TestAssembler(BaseTestAssembler): + def imm_4_int32(self, a, b, c, d): adr = self.xrm.assembler.datablockwrapper.malloc_aligned(16, 16) ptr = rffi.cast(rffi.CArrayPtr(rffi.INT), adr) diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -568,7 +568,7 @@ args = op.getarglist() base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args) ofs_loc = self.rm.make_sure_var_in_reg(op.getarg(1), args) - result_loc = self.force_allocate_reg(op.result) + result_loc = self.force_allocate_reg(op) self.perform(op, [base_loc, ofs_loc, imm(itemsize), imm(ofs), imm(integer), imm(aligned)], result_loc) @@ -601,11 +601,10 @@ def consider_vec_arith(self, op): lhs = op.getarg(0) - assert isinstance(lhs, BoxVector) - size = lhs.item_size + size = lhs.bytesize args = op.getarglist() loc1 = self.make_sure_var_in_reg(op.getarg(1), args) - loc0 = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) + loc0 = self.xrm.force_result_in_reg(op, op.getarg(0), args) self.perform(op, [loc0, loc1, imm(size)], loc0) consider_vec_int_add = consider_vec_arith @@ -622,7 +621,7 @@ assert isinstance(lhs, BoxVector) size = lhs.item_size args = op.getarglist() - res = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) + res = self.xrm.force_result_in_reg(op, op.getarg(0), args) self.perform(op, [res, imm(size)], res) consider_vec_float_neg = consider_vec_arith_unary @@ -631,19 +630,17 @@ def consider_vec_logic(self, op): lhs = op.getarg(0) - assert isinstance(lhs, BoxVector) - size = lhs.item_size args = op.getarglist() source = self.make_sure_var_in_reg(op.getarg(1), args) - result = self.force_result_in_reg(op.result, op.getarg(0), args) - self.perform(op, [source, imm(size)], result) + result = self.xrm.force_result_in_reg(op, op.getarg(0), args) + self.perform(op, [source, imm(lhs.bytesize)], result) def consider_vec_float_eq(self, op, guard_op): lhs = op.getarg(0) assert isinstance(lhs, BoxVector) size = lhs.item_size args = op.getarglist() - lhsloc = self.force_result_in_reg(op.result, op.getarg(0), args) + lhsloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) rhsloc = self.make_sure_var_in_reg(op.getarg(1), args) if guard_op: self.perform_with_guard(op, guard_op, [lhsloc, rhsloc, imm(size)], None) @@ -668,12 +665,11 @@ assert isinstance(count, ConstInt) args = op.getarglist() srcloc = self.make_sure_var_in_reg(arg, args) - resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) + resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) residx = index.value # where to put it in result? srcidx = 0 - assert isinstance(op.result, BoxVector) - size = op.result.getsize() - arglocs = [resloc, srcloc, imm(residx), imm(srcidx), imm(count.value), imm(size)] + arglocs = [resloc, srcloc, imm(residx), imm(srcidx), + imm(count.value), imm(op.bytesize)] self.perform(op, arglocs, resloc) consider_vec_pack_f = consider_vec_pack_i @@ -703,19 +699,15 @@ consider_vec_unpack_f = consider_vec_unpack_i def consider_vec_expand_f(self, op): - result = op.result - assert isinstance(result, BoxVector) arg = op.getarg(0) args = op.getarglist() if arg.is_constant(): - resloc = self.xrm.force_allocate_reg(result) - srcloc = self.xrm.expand_float(result.getsize(), arg) + resloc = self.xrm.force_allocate_reg(op) + srcloc = self.xrm.expand_float(op.bytesize, arg) else: - resloc = self.xrm.force_result_in_reg(op.result, arg, args) + resloc = self.xrm.force_result_in_reg(op, arg, args) srcloc = resloc - - size = op.result.getsize() - self.perform(op, [srcloc, imm(size)], resloc) + self.perform(op, [srcloc, imm(op.bytesize)], resloc) def consider_vec_expand_i(self, op): arg = op.getarg(0) @@ -724,21 +716,15 @@ srcloc = self.rm.convert_to_imm(arg) else: srcloc = self.make_sure_var_in_reg(arg, args) - resloc = self.xrm.force_allocate_reg(op.result, args) - assert isinstance(op.result, BoxVector) - size = op.result.getsize() - self.perform(op, [srcloc, imm(size)], resloc) + resloc = self.xrm.force_allocate_reg(op, args) + self.perform(op, [srcloc, imm(op.bytesize)], resloc) def consider_vec_int_signext(self, op): args = op.getarglist() - resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) - sizearg = op.getarg(0) - result = op.result - assert isinstance(sizearg, BoxVector) - assert isinstance(result, BoxVector) - size = sizearg.getsize() - tosize = result.getsize() - self.perform(op, [resloc, imm(size), imm(tosize)], resloc) + resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) + size = op.cast_from_bytesize() + assert size > 0 + self.perform(op, [resloc, imm(size), imm(op.bytesize)], resloc) def consider_vec_int_is_true(self, op, guard_op): args = op.getarglist() @@ -753,8 +739,8 @@ def _consider_vec(self, op): # pseudo instruction, needed to create a new variable - self.xrm.force_allocate_reg(op.result) - + self.xrm.force_allocate_reg(op) + consider_vec_i = _consider_vec consider_vec_f = _consider_vec @@ -764,7 +750,7 @@ def consider_vec_cast_float_to_int(self, op): args = op.getarglist() srcloc = self.make_sure_var_in_reg(op.getarg(0), args) - resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) + resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) self.perform(op, [srcloc], resloc) consider_vec_cast_int_to_float = consider_vec_cast_float_to_int diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -301,7 +301,8 @@ from rpython.jit.metainterp.optimizeopt.vector import optimize_vector loop_info, loop_ops = optimize_vector(metainterp_sd, jitdriver_sd, warmstate, - loop_info, loop_ops) + loop_info, loop_ops, + jitcell_token) # loop = create_empty_loop(metainterp) loop.original_jitcell_token = jitcell_token diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -122,7 +122,6 @@ break i -= 1 else: - print "insert at 0", target worklist.insert(0, target) node.clear_dependencies() node.emitted = True @@ -379,7 +378,6 @@ def unpack_from_vector(state, arg, index, count): """ Extract parts of the vector box into another vector box """ - #print "unpack i", index, "c", count, "v", arg assert count > 0 assert index + count <= arg.count args = [arg, ConstInt(index), ConstInt(count)] @@ -555,9 +553,7 @@ descr.rd_accum_list = AccumInfo(descr.rd_accum_list, i, accum.operator, arg, None) seed = accum.getleftmostseed() - print "pre", failargs[i], "=>", failargs[i] = self.renamer.rename_map.get(seed, seed) - print failargs[i] def profitable(self): return self.costmodel.profitable() @@ -613,7 +609,6 @@ if argument and not argument.is_constant(): arg = self.ensure_unpacked(i, argument) if argument is not arg: - print "exchange at", i, fail_args[i], "=", arg fail_args[i] = arg def ensure_unpacked(self, index, arg): @@ -780,12 +775,10 @@ vector register. """ before_count = len(packlist) - print "splitting pack", self pack = self while pack.pack_load(vec_reg_size) > Pack.FULL: pack.clear() oplist, newoplist = pack.slice_operations(vec_reg_size) - print " split of %dx, left: %d" % (len(oplist), len(newoplist)) pack.operations = oplist pack.update_pack_of_nodes() if not pack.leftmost().is_typecast(): @@ -801,7 +794,6 @@ newpack.clear() newpack.operations = [] break - print " => %dx packs out of %d operations" % (-before_count + len(packlist) + 1, sum([pack.numops() for pack in packlist[before_count:]])) pack.update_pack_of_nodes() def slice_operations(self, vec_reg_size): diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -44,19 +44,22 @@ self.jump = jump assert self.jump.getopnum() == rop.JUMP - def finaloplist(self, jitcell_token=None, label=False): + def finaloplist(self, jitcell_token=None, reset_label_token=True, label=False): oplist = [] if jitcell_token: - token = TargetToken(jitcell_token) - token.original_jitcell_token = jitcell_token - jitcell_token.target_tokens.append(token) - self.label.setdescr(token) + if reset_label_token: + token = TargetToken(jitcell_token) + token.original_jitcell_token = jitcell_token + jitcell_token.target_tokens.append(token) + self.label.setdescr(token) if self.prefix_label: token = TargetToken(jitcell_token) token.original_jitcell_token = jitcell_token jitcell_token.target_tokens.append(token) self.prefix_label.setdescr(token) - self.jump.setdescr(token) + self.jump.setdescr(token) + if reset_label_token: + self.jump.setdescr(token) if self.prefix_label: oplist = self.prefix + [self.prefix_label] elif self.prefix: @@ -93,7 +96,8 @@ loop.prefix_label = prefix_label return loop -def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, loop_info, loop_ops): +def optimize_vector(metainterp_sd, jitdriver_sd, warmstate, + loop_info, loop_ops, jitcell_token=None): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ user_code = not jitdriver_sd.vec and warmstate.vec_all loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) @@ -122,7 +126,7 @@ debug_stop("vec-opt-loop") # info.label_op = loop.label - return info, loop.finaloplist() + return info, loop.finaloplist(jitcell_token=jitcell_token, reset_label_token=False) except NotAVectorizeableLoop: debug_stop("vec-opt-loop") # vectorization is not possible diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -112,62 +112,10 @@ else: assert 0, "olddescr must be found" - def update_token(self, jitcell_token, all_target_tokens): - # this is only invoked for versioned loops! - # TODO - label_index = index_of_first(rop.LABEL, self.operations, 0) - label = self.operations[label_index] - jump = self.operations[-1] - # - assert jump.getopnum() == rop.JUMP - # - token = TargetToken(jitcell_token) - token.original_jitcell_token = jitcell_token - all_target_tokens.append(token) - if label.getdescr() is None or label.getdescr() is not jump.getdescr(): - label_index = index_of_first(rop.LABEL, self.operations, 1) - if label_index > 0: - second_label = self.operations[label_index] - # set the inner loop - second_label.setdescr(token) - jump.setdescr(token) - # set the first label - token = TargetToken(jitcell_token) - token.original_jitcell_token = jitcell_token - all_target_tokens.append(token) - label.setdescr(token) - return - label.setdescr(token) - jump.setdescr(token) - def create_backend_loop(self, metainterp, jitcell_token): vl = create_empty_loop(metainterp) - vl.operations = self.loop.finaloplist(jitcell_token,True) + vl.operations = self.loop.finaloplist(jitcell_token,True,True) vl.inputargs = self.loop.label.getarglist_copy() vl.original_jitcell_token = jitcell_token return vl - -#def index_of_first(opnum, operations, pass_by=0): -# """ returns the position of the first operation matching the opnum. -# Or -1 if non is found -# """ -# for i,op in enumerate(operations): -# if op.getopnum() == opnum: -# if pass_by == 0: -# return i -# else: -# pass_by -= 1 -# return -1 -# -#def find_first_index(self, opnum, pass_by=0): -# """ return the first index of the operation having the same opnum or -1 """ -# return index_of_first(opnum, self.operations, pass_by) -# -#def find_first(self, opnum, pass_by=0): -# index = self.find_first_index(opnum, pass_by) -# if index != -1: -# return self.operations[index] -# return None - - diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -1185,12 +1185,15 @@ _cast_ops = { 'CAST_FLOAT_TO_INT': ('f', 8, 'i', 4, 2), + 'VEC_CAST_FLOAT_TO_INT': ('f', 8, 'i', 4, 2), 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8, 2), + 'VEC_CAST_INT_TO_FLOAT': ('i', 4, 'f', 8, 2), 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4, 2), + 'VEC_CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4, 2), 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8, 2), + 'VEC_CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8, 2), 'INT_SIGNEXT': ('i', 0, 'i', 0, 0), - #'CAST_PTR_TO_INT': ('r', 0, 'i', 4), - #'CAST_INT_TO_PTR': ('i', 4, 'r', 0), + 'VEC_INT_SIGNEXT': ('i', 0, 'i', 0, 0), } # ____________________________________________________________ @@ -1292,7 +1295,7 @@ else: assert result_type == 'n' if name in _cast_ops: - if name == "INT_SIGNEXT": + if "INT_SIGNEXT" in name: mixins.append(SignExtOp) mixins.append(CastOp) @@ -1302,7 +1305,6 @@ return type(cls_name, bases, dic) setup(__name__ == '__main__') # print out the table when run directly -del _oplist _opboolinverse = { rop.INT_EQ: rop.INT_NE, diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -57,6 +57,9 @@ self.scalar_box = box self.vector_loc = loc + def getoriginal(self): + return self.scalar_box + def getpos_in_failargs(self): return self.scalar_position From noreply at buildbot.pypy.org Thu Sep 24 18:32:49 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Thu, 24 Sep 2015 18:32:49 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: removes the unused faildescr from the versioned loop info Message-ID: <20150924163249.E676B1C1277@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79813:5fa27b9b5c0c Date: 2015-09-24 18:33 +0200 http://bitbucket.org/pypy/pypy/changeset/5fa27b9b5c0c/ Log: removes the unused faildescr from the versioned loop info diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1750,7 +1750,7 @@ genop_guard_guard_no_overflow = genop_guard_guard_true genop_guard_guard_overflow = genop_guard_guard_false - def genop_guard_guard_value(self, ign_1, guard_op, guard_token, locs, ign_2): + def genop_guard_guard_value(self, guard_op, guard_token, locs, ign): if guard_op.getarg(0).type == FLOAT: assert guard_op.getarg(1).type == FLOAT self.mc.UCOMISD(locs[0], locs[1]) diff --git a/rpython/jit/backend/x86/test/test_x86vector.py b/rpython/jit/backend/x86/test/test_x86vector.py --- a/rpython/jit/backend/x86/test/test_x86vector.py +++ b/rpython/jit/backend/x86/test/test_x86vector.py @@ -18,10 +18,14 @@ clazz = self.CPUClass def init(*args, **kwargs): cpu = clazz(*args, **kwargs) + # > 95% can be executed, thus let's cheat here a little cpu.supports_guard_gc_type = True return cpu self.CPUClass = init + def test_list_vectorize(self): + pass # needs support_guard_gc_type, disable for now + enable_opts = 'intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll' class TestAssembler(BaseTestAssembler): diff --git a/rpython/jit/metainterp/optimizeopt/guard.py b/rpython/jit/metainterp/optimizeopt/guard.py --- a/rpython/jit/metainterp/optimizeopt/guard.py +++ b/rpython/jit/metainterp/optimizeopt/guard.py @@ -313,6 +313,7 @@ if transitive_guard: if version is None: version = info.snapshot(loop) + info.remove(other.op.getdescr()) other.set_to_none(info, loop) descr = transitive_guard.getdescr() assert isinstance(descr, ResumeGuardDescr) diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -30,6 +30,7 @@ self.descrs.insert(i, descr) else: self.descrs.append(descr) + assert descr not in self.leads_to self.leads_to[descr] = version assert version.renamed_inputargs is not None From noreply at buildbot.pypy.org Thu Sep 24 21:11:40 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Thu, 24 Sep 2015 21:11:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Expose numpy.flagsobj as _numpypy.multiarray.flagsobj Message-ID: <20150924191140.4CB481C06AD@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Changeset: r79814:dd5cf28797b0 Date: 2015-09-24 20:11 +0100 http://bitbucket.org/pypy/pypy/changeset/dd5cf28797b0/ Log: Expose numpy.flagsobj as _numpypy.multiarray.flagsobj diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -9,6 +9,7 @@ 'ndarray': 'ndarray.W_NDimArray', 'dtype': 'descriptor.W_Dtype', 'flatiter': 'flatiter.W_FlatIterator', + 'flagsobj': 'flagsobj.W_FlagsObject', '_reconstruct' : 'ndarray._reconstruct', 'scalar' : 'ctors.build_scalar', From noreply at buildbot.pypy.org Thu Sep 24 22:42:20 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 22:42:20 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150924204220.5D55F1C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r639:626601a92b87 Date: 2015-09-24 22:43 +0200 http://bitbucket.org/pypy/pypy.org/changeset/626601a92b87/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -15,7 +15,7 @@ - $60560 of $105000 (57.7%) + $60561 of $105000 (57.7%)
    From noreply at buildbot.pypy.org Thu Sep 24 23:01:11 2015 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 24 Sep 2015 23:01:11 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move: in-progress Message-ID: <20150924210111.661FF1C1277@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move Changeset: r79815:d9733b69dd6b Date: 2015-09-24 23:01 +0200 http://bitbucket.org/pypy/pypy/changeset/d9733b69dd6b/ Log: in-progress diff --git a/rpython/rlib/_rffi_stacklet.py b/rpython/rlib/_rffi_stacklet.py --- a/rpython/rlib/_rffi_stacklet.py +++ b/rpython/rlib/_rffi_stacklet.py @@ -43,6 +43,8 @@ # ----- functions ----- newthread = llexternal('stacklet_newthread', [], thread_handle) +newthread_shadowstack = llexternal('stacklet_newthread_shadowstack', + [rffi.VOIDPP], thread_handle) deletethread = llexternal('stacklet_deletethread',[thread_handle], lltype.Void) new = llexternal('stacklet_new', [thread_handle, run_fn, llmemory.Address], @@ -54,3 +56,7 @@ _translate_pointer = llexternal("_stacklet_translate_pointer", [llmemory.Address, llmemory.Address], llmemory.Address) +get_saved_shadow = llexternal("_stacklet_get_saved_shadow", + [handle], llmemory.Address) +get_saved_shadow_size = llexternal("_stacklet_get_saved_shadow_size", + [handle], lltype.Signed) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -251,6 +251,10 @@ class StackletGcRootFinder(object): suspstack = NULL_SUSPSTACK + @staticmethod + def newthread(): + return _c.newthread() + def new(self, thrd, callback, arg): self.newthrd = thrd._thrd self.runfn = callback diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -1,104 +1,124 @@ from rpython.rlib import _rffi_stacklet as _c +from rpython.rlib import rgc from rpython.rlib.debug import ll_assert from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.lltypesystem.lloperation import llop -NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO) +# +# A GC wrapper around the C stacklet handles +# +STACKLET = lltype.GcStruct('Stacklet', + ('handle', _c.handle), + rtti=True) +STACKLET_PTR = lltype.Ptr(STACKLET) +NULL_STACKLET = lltype.nullptr(STACKLET) +sizeofaddr = llmemory.sizeof(llmemory.Address) + + +def complete_destrptr(gctransformer): + translator = gctransformer.translator + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + args_s = [lltype_to_annotation(STACKLET_PTR)] + s_result = annmodel.s_None + destrptr = mixlevelannotator.delayedfunction(stacklet_destructor, + args_s, s_result) + mixlevelannotator.finish() + lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr) + +def customtrace(gc, obj, callback, arg): + stacklet = llmemory.cast_adr_to_ptr(obj, STACKLET_PTR) + h = stacklet.handle + if h: + addr = _c.get_saved_shadow(h) + stop = addr + _c.get_saved_shadow_size(h) + while addr != stop: + gc._trace_callback(callback, arg, addr) + addr += sizeofaddr +lambda_customtrace = lambda: customtrace + +def stacklet_destructor(stacklet): + h = stacklet.handle + if h: + _c.destroy(h) + + +def alloc_stacklet(): + new_stacklet = lltype.malloc(STACKLET) + new_stacklet.handle = _c.null_handle + return new_stacklet + +def attach_handle_on_stacklet(stacklet, h): + if not h: + raise MemoryError + elif _c.is_empty_handle(h): + return NULL_STACKLET + else: + # This is a return that gave us a real handle. Store it. + stacklet.handle = h + llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(stacklet)) + return stacklet + +def consume_stacklet(stacklet): + h = stacklet.handle + ll_assert(bool(h), "consume_stacklet: null handle") + stacklet.handle = _c.null_handle + return h def _new_callback(h, arg): - # We still have the old shadowstack active at this point; save it - # away, and start a fresh new one - oldsuspstack = gcrootfinder.oldsuspstack - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, - oldsuspstack, h) - llop.gc_start_fresh_new_state(lltype.Void) - gcrootfinder.oldsuspstack = NULL_SUSPSTACK + # There is a fresh stacklet object waiting on the gcrootfinder, + # so populate it with data that represents the parent suspended + # stacklet and detach the stacklet object from gcrootfinder. + stacklet = gcrootfinder.fresh_stacklet + gcrootfinder.fresh_stacklet = NULL_STACKLET + stacklet = attach_handle_on_stacklet(stacklet, h) + assert stacklet # - newsuspstack = gcrootfinder.callback(oldsuspstack, arg) + # Call the main function provided by the (RPython) user. + stacklet = gcrootfinder.runfn(stacklet, arg) # - # Finishing this stacklet. - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = newsuspstack - h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack) - return llmemory.cast_adr_to_ptr(h, _c.handle) - -def prepare_old_suspstack(): - if not gcrootfinder.oldsuspstack: # else reuse the one still there - _allocate_old_suspstack() - -def _allocate_old_suspstack(): - suspstack = llop.gc_shadowstackref_new(llmemory.GCREF) - gcrootfinder.oldsuspstack = suspstack -_allocate_old_suspstack._dont_inline_ = True - -def get_result_suspstack(h): - # Now we are in the target, after the switch() or the new(). - # Note that this whole module was carefully written in such a way as - # not to invoke pushing/popping things off the shadowstack at - # unexpected moments... - oldsuspstack = gcrootfinder.oldsuspstack - newsuspstack = gcrootfinder.newsuspstack - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = NULL_SUSPSTACK - if not h: - raise MemoryError - # We still have the old shadowstack active at this point; save it - # away, and restore the new one - if oldsuspstack: - ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle") - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, oldsuspstack, h) - else: - ll_assert(_c.is_empty_handle(h),"unexpected non-empty stacklet handle") - llop.gc_forget_current_state(lltype.Void) - # - llop.gc_restore_state_from(lltype.Void, newsuspstack) - # - # From this point on, 'newsuspstack' is consumed and done, its - # shadow stack installed as the current one. It should not be - # used any more. For performance, we avoid it being deallocated - # by letting it be reused on the next switch. - gcrootfinder.oldsuspstack = newsuspstack - # Return. - return oldsuspstack + # Here, 'stacklet' points to the target stacklet to which we want + # to jump to next. Read the 'handle' and forget about the + # stacklet object. + return consume_stacklet(stacklet) class StackletGcRootFinder(object): + fresh_stacklet = NULL_STACKLET + + @staticmethod + def newthread(): + rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address) + return _c.newthread_shadowstack(rffi.cast(rffi.VOIDPP, rst_addr)) + def new(thrd, callback, arg): - gcrootfinder.callback = callback + rgc.register_custom_trace_hook(STACKLET, lambda_customtrace) + result_stacklet = alloc_stacklet() + gcrootfinder.fresh_stacklet = alloc_stacklet() + gcrootfinder.runfn = callback thread_handle = thrd._thrd - prepare_old_suspstack() h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) - return get_result_suspstack(h) + return attach_handle_on_stacklet(result_stacklet, h) new._dont_inline_ = True new = staticmethod(new) - def switch(suspstack): - # suspstack has a handle to target, i.e. where to switch to - ll_assert(suspstack != gcrootfinder.oldsuspstack, - "stacklet: invalid use") - gcrootfinder.newsuspstack = suspstack - h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) - h = llmemory.cast_adr_to_ptr(h, _c.handle) - prepare_old_suspstack() + def switch(stacklet): + # 'stacklet' has a handle to target, i.e. where to switch to + h = consume_stacklet(stacklet) h = _c.switch(h) - return get_result_suspstack(h) + return attach_handle_on_stacklet(stacklet, h) switch._dont_inline_ = True switch = staticmethod(switch) @staticmethod - def is_empty_handle(suspstack): - return not suspstack + def is_empty_handle(stacklet): + return not stacklet @staticmethod def get_null_handle(): - return NULL_SUSPSTACK + return NULL_STACKLET gcrootfinder = StackletGcRootFinder() -gcrootfinder.oldsuspstack = NULL_SUSPSTACK -gcrootfinder.newsuspstack = NULL_SUSPSTACK diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py --- a/rpython/rlib/rstacklet.py +++ b/rpython/rlib/rstacklet.py @@ -12,7 +12,7 @@ @jit.dont_look_inside def __init__(self, config): self._gcrootfinder = _getgcrootfinder(config, we_are_translated()) - self._thrd = _c.newthread() + self._thrd = self._gcrootfinder.newthread() if not self._thrd: raise MemoryError self._thrd_deleter = StackletThreadDeleter(self._thrd) diff --git a/rpython/translator/c/src/stacklet/stacklet.c b/rpython/translator/c/src/stacklet/stacklet.c --- a/rpython/translator/c/src/stacklet/stacklet.c +++ b/rpython/translator/c/src/stacklet/stacklet.c @@ -226,6 +226,16 @@ thrd->g_stack_chain_head = current; } +static void move_shadow_stack_ref(struct stacklet_thread_s *thrd, char *target) +{ + if (thrd->g_shadow_stack_ref != NULL) { + char *source = *thrd->g_shadow_stack_ref; + if (target > source) + memset(source, 0, target - source); + *thrd->g_shadow_stack_ref = target; + } +} + /* This saves the current state in a new stacklet that gets stored in * 'g_source', and save away enough of the stack to allow a jump to * 'g_target'. @@ -236,8 +246,7 @@ if (g_allocate_source_stacklet(old_stack_pointer, thrd) < 0) return NULL; g_clear_stack(thrd->g_target, thrd); - if (thrd->g_shadow_stack_ref != NULL) - *thrd->g_shadow_stack_ref = thrd->g_target->shadow_stack_start; + move_shadow_stack_ref(thrd, thrd->g_target->shadow_stack_start); return thrd->g_target->stack_start; } @@ -264,8 +273,7 @@ struct stacklet_thread_s *thrd = (struct stacklet_thread_s *)rawthrd; thrd->g_source = EMPTY_STACKLET_HANDLE; g_clear_stack(thrd->g_target, thrd); - if (thrd->g_shadow_stack_ref != NULL) - *thrd->g_shadow_stack_ref = thrd->g_target->shadow_stack_start; + move_shadow_stack_ref(thrd, thrd->g_target->shadow_stack_start); return thrd->g_target->stack_start; } @@ -447,28 +455,15 @@ return ptr; } -char **_stacklet_translate_shadow_pointer(stacklet_handle context, char **ptr) +char *_stacklet_get_saved_shadow(stacklet_handle context) { - char *p = (char *)ptr; - long delta; - if (context == NULL) - return ptr; - delta = context->shadow_stack_start - p; - if (((unsigned long)(delta - 1)) < - ((unsigned long)context->shadow_stack_saved)) { - /* a pointer to a saved away word */ - char *end = ((char *)(context + 1)) + - (context->stack_stop - context->stack_start) + - (context->shadow_stack_start - context->shadow_stack_stop); - return (char **)(end - delta); - } - if (((unsigned long)delta) > (unsigned long)(context->shadow_stack_start - - context->shadow_stack_stop)) { - /* out-of-stack pointer! it's only ok if we are the main stacklet - and we are reading past the end, because the main stacklet's - stack stop is not exactly known. */ - assert(delta >= 0); - assert(((long)context->stack_stop) & 1); - } - return ptr; + char *end = ((char *)(context + 1)) + + (context->stack_stop - context->stack_start) + + (context->shadow_stack_start - context->shadow_stack_stop); + return end - context->shadow_stack_saved; } + +long _stacklet_get_saved_shadow_size(stacklet_handle context) +{ + return context->shadow_stack_saved; +} diff --git a/rpython/translator/c/src/stacklet/stacklet.h b/rpython/translator/c/src/stacklet/stacklet.h --- a/rpython/translator/c/src/stacklet/stacklet.h +++ b/rpython/translator/c/src/stacklet/stacklet.h @@ -69,7 +69,10 @@ */ RPY_EXTERN char **_stacklet_translate_pointer(stacklet_handle context, char **ptr); -RPY_EXTERN -char **_stacklet_translate_shadow_pointer(stacklet_handle context, char **ptr); + +/* Hack for shadowstack: fish the portion of shadowstack that is stored + in some stacklet_handle */ +RPY_EXTERN char *_stacklet_get_saved_shadow(stacklet_handle context); +RPY_EXTERN long _stacklet_get_saved_shadow_size(stacklet_handle context); #endif /* _STACKLET_H_ */ diff --git a/rpython/translator/c/src/stacklet/tests.c b/rpython/translator/c/src/stacklet/tests.c --- a/rpython/translator/c/src/stacklet/tests.c +++ b/rpython/translator/c/src/stacklet/tests.c @@ -655,6 +655,7 @@ status = 5; assert(shadowstack_top == my_shadowstack + 3); + assert(my_shadowstack[0] != 9999); assert(my_shadowstack[1] == 1001); assert(my_shadowstack[2] == 1002); trash_more_shadowstack(); @@ -681,6 +682,8 @@ status = 6; assert(shadowstack_top == my_shadowstack + 4); + assert(my_shadowstack[0] != 9999); + assert(my_shadowstack[1] != 9999); assert(my_shadowstack[2] == 2002); assert(my_shadowstack[3] == 2003); trash_more_shadowstack(); @@ -745,6 +748,56 @@ shadowstack_top -= 5; } +void test_shadowstack_clear(void) +{ + status = 0; + shadowstack_top = my_shadowstack; + *shadowstack_top++ = 500; + trash_more_shadowstack(); + + stacklet_handle h = stacklet_new(thrd, switchbackonce_callback_shadow_1, + (void *)123); + assert(h != EMPTY_STACKLET_HANDLE); + assert(status == 1); + status = 2; + + assert(shadowstack_top == my_shadowstack + 1); + assert(my_shadowstack[0] == 500); + *shadowstack_top++ = 501; + trash_more_shadowstack(); + + stacklet_handle h2 = stacklet_new(thrd, switchbackonce_callback_shadow_2, + (void *)456); + assert(h2 != EMPTY_STACKLET_HANDLE); + assert(status == 3); + status = 4; + + assert(shadowstack_top == my_shadowstack + 2); + assert(my_shadowstack[0] == 500); + assert(my_shadowstack[1] == 501); + shadowstack_top -= 2; + my_shadowstack[0] = 9999; + my_shadowstack[1] = 9999; + my_shadowstack[2] = 9999; + my_shadowstack[3] = 9999; + + h = stacklet_switch(h); + assert(status == 5); + assert(h == EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack); + my_shadowstack[0] = 9999; + my_shadowstack[1] = 9999; + my_shadowstack[2] = 9999; + my_shadowstack[3] = 9999; + + h2 = stacklet_switch(h2); + assert(status == 6); + assert(h2 == EMPTY_STACKLET_HANDLE); + + assert(shadowstack_top == my_shadowstack); +} + /************************************************************/ #define TEST(name) { name, #name } @@ -770,6 +823,7 @@ TEST(test_random), #endif TEST(test_shadowstack), + TEST(test_shadowstack_clear), { NULL, NULL } }; From noreply at buildbot.pypy.org Fri Sep 25 08:21:54 2015 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 25 Sep 2015 08:21:54 +0200 (CEST) Subject: [pypy-commit] pypy default: export, test ndarray.flags.num Message-ID: <20150925062154.752A21C134D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79816:d9a0ad02e94c Date: 2015-09-25 09:21 +0300 http://bitbucket.org/pypy/pypy/changeset/d9a0ad02e94c/ Log: export, test ndarray.flags.num diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -147,7 +147,7 @@ def get_flags(self): return (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS | - NPY.ARRAY_WRITEABLE | NPY.ARRAY_OWNDATA) + NPY.ARRAY_ALIGNED | NPY.ARRAY_OWNDATA) def item(self, space): return self.get_dtype(space).itemtype.to_builtin_type(space, self) diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py --- a/pypy/module/micronumpy/flagsobj.py +++ b/pypy/module/micronumpy/flagsobj.py @@ -57,6 +57,9 @@ self.flags & NPY.ARRAY_F_CONTIGUOUS or self.flags & NPY.ARRAY_C_CONTIGUOUS )) + def descr_get_num(self, space): + return space.wrap(self.flags) + def descr_getitem(self, space, w_item): key = space.str_w(w_item) if key == "C" or key == "CONTIGUOUS" or key == "C_CONTIGUOUS": @@ -122,4 +125,5 @@ aligned = GetSetProperty(W_FlagsObject.descr_get_aligned), fnc = GetSetProperty(W_FlagsObject.descr_get_fnc), forc = GetSetProperty(W_FlagsObject.descr_get_forc), + num = GetSetProperty(W_FlagsObject.descr_get_num), ) diff --git a/pypy/module/micronumpy/test/test_flagsobj.py b/pypy/module/micronumpy/test/test_flagsobj.py --- a/pypy/module/micronumpy/test/test_flagsobj.py +++ b/pypy/module/micronumpy/test/test_flagsobj.py @@ -30,6 +30,7 @@ assert a.flags.forc == True assert a.flags['FNC'] == False assert a.flags['FORC'] == True + assert a.flags.num == 1287 raises(KeyError, "a.flags['blah']") raises(KeyError, "a.flags['C_CONTIGUOUS'] = False") raises((TypeError, AttributeError), "a.flags.c_contiguous = False") @@ -38,6 +39,7 @@ import numpy as np a = np.int32(2) assert a.flags.c_contiguous == True + assert a.flags.num == 263 def test_compare(self): import numpy as np From noreply at buildbot.pypy.org Fri Sep 25 09:23:20 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 09:23:20 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: wunderbar! x86 assembler works for all the test_x86vector tests Message-ID: <20150925072320.2609A1C134D@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79817:84a252c28c3b Date: 2015-09-25 09:23 +0200 http://bitbucket.org/pypy/pypy/changeset/84a252c28c3b/ Log: wunderbar! x86 assembler works for all the test_x86vector tests diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -556,6 +556,7 @@ self.current_clt.allgcrefs, self.current_clt.frame_info) self._check_frame_depth(self.mc, regalloc.get_gcmap()) + bridgestartpos = self.mc.get_relative_pos() self._accum_update_at_exit(arglocs, inputargs, faildescr, regalloc) frame_depth_no_fixed_size = self._assemble(regalloc, inputargs, operations) codeendpos = self.mc.get_relative_pos() @@ -583,7 +584,8 @@ name = "Bridge # %s" % (descr_number,) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) - return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos, rawstart) + print "bridge pos", hex(startpos+rawstart), hex(rawstart+bridgestartpos), startpos + return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos, rawstart+bridgestartpos) def stitch_bridge(self, faildescr, target): """ Stitching means that one can enter a bridge with a complete different register @@ -607,6 +609,7 @@ # if accumulation is saved at the guard, we need to update it here! guard_locs = self.rebuild_faillocs_from_descr(faildescr, version.inputargs) bridge_locs = self.rebuild_faillocs_from_descr(bridge_faildescr, version.inputargs) + #import pdb; pdb.set_trace() guard_accum_info = faildescr.rd_accum_list # O(n^2), but usually you only have at most 1 fail argument while guard_accum_info: @@ -636,6 +639,7 @@ rawstart = self.materialize_loop(looptoken) # update the jump to the real trace self._patch_jump_for_descr(rawstart + offset, asminfo.rawstart) + print faildescr, "=>", hex(asminfo.rawstart) # update the guard to jump right to this custom piece of assembler self.patch_jump_for_descr(faildescr, rawstart) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -701,7 +701,8 @@ self.rd_pendingfields = other.rd_pendingfields self.rd_virtuals = other.rd_virtuals self.rd_numb = other.rd_numb - self.rd_accum_list = other.rd_accum_list + if other.rd_accum_list: + self.rd_accum_list = other.rd_accum_list.clone() # we don't copy status ST_BUSY_FLAG = 0x01 # if set, busy tracing from the guard diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -66,6 +66,13 @@ def next(self): return self.prev + def clone(self): + prev = None + if self.prev: + prev = self.prev.clone() + return AccumInfo(prev, self.scalar_position, self.accum_operation, + self.scalar_box, None) + def __repr__(self): return 'AccumInfo(%s,%s,%s,%s,%s)' % (self.prev is None, self.accum_operation, From noreply at buildbot.pypy.org Fri Sep 25 10:50:52 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 10:50:52 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: 7 new test cases to check the guard_true/false assembler for vector parameters Message-ID: <20150925085052.73B341C135E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79818:fd5cdd7ddc3e Date: 2015-09-25 10:51 +0200 http://bitbucket.org/pypy/pypy/changeset/fd5cdd7ddc3e/ Log: 7 new test cases to check the guard_true/false assembler for vector parameters diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -118,20 +118,6 @@ retval = self.interp.eval_graph(self.graph, [i]) return retval - def define_dot_matrix(): - return """ - mat = |16| - m = reshape(mat, [4,4]) - vec = [0,1,2,3] - a = dot(m, vec) - a -> 3 - """ - - def test_dot_matrix(self): - result = self.run("dot_matrix") - assert int(result) == 86 - self.check_vectorized(2, 1) - def define_float32_copy(): return """ a = astype(|30|, float32) @@ -916,6 +902,21 @@ # that iterates continous chunks of the matrix self.check_vectorized(1,1) + def define_dot_matrix(): + return """ + mat = |16| + m = reshape(mat, [4,4]) + vec = [0,1,2,3] + a = dot(m, vec) + a -> 3 + """ + + def test_dot_matrix(self): + result = self.run("dot_matrix") + assert int(result) == 86 + self.check_vectorized(2, 1) + + # NOT WORKING def define_pow(): 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 @@ -1075,12 +1075,22 @@ def execute_guard_early_exit(self, descr): pass + def _check_true(self, arg): + if isinstance(arg, list): + return all(arg) + return arg + + def _check_false(self, arg): + if isinstance(arg, list): + return any(arg) + return arg + def execute_guard_true(self, descr, arg): - if not arg: + if not self._check_true(arg): self.fail_guard(descr) def execute_guard_false(self, descr, arg): - if arg: + if self._check_false(arg): self.fail_guard(descr) def execute_guard_value(self, descr, arg1, arg2): 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 @@ -248,7 +248,7 @@ all_interiorfielddescrs = None concrete_type = '\x00' - def __init__(self, basesize, itemsize, lendescr, flag, concrete_type='\x00', is_pure=False): + def __init__(self, basesize, itemsize, lendescr, flag, is_pure=False, concrete_type='\x00'): self.basesize = basesize self.itemsize = itemsize self.lendescr = lendescr # or None, if no length @@ -339,13 +339,13 @@ descrs = heaptracker.all_interiorfielddescrs(gccache, ARRAY_INSIDE, get_field_descr=get_interiorfield_descr) arraydescr.all_interiorfielddescrs = descrs - concreate_type = '\x00' + concrete_type = '\x00' if ARRAY_INSIDE.OF is lltype.SingleFloat or \ ARRAY_INSIDE.OF is lltype.Float: # it would be better to set the flag as FLOAT_TYPE # for single float -> leads to problems - concrete_type = FLOAT - arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag, concreate_type) + concrete_type = 'f' + arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag, is_pure, concrete_type=concrete_type) if ARRAY_OR_STRUCT._gckind == 'gc': gccache.init_array_descr(ARRAY_OR_STRUCT, arraydescr) return arraydescr diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1658,14 +1658,6 @@ self.mc.PUNPCKLDQ_xx(resloc.value, loc1.value) def genop_guard_guard_true(self, guard_op, guard_token, locs, resloc): - #loc = locs[0] - #if isinstance(loc, RegLoc): - # if loc.is_xmm: - # self._guard_vector_true(guard_op, loc) - # # XXX - # self.implement_guard(guard_token, 'NZ') - # return - #self.mc.TEST(loc, loc) self.implement_guard(guard_token) genop_guard_guard_nonnull = genop_guard_guard_true diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -43,9 +43,9 @@ self.mc.PBLENDW_xxi(loc.value, temp.value, select) def _guard_vector_true(self, guard_op, loc, zero=False): + return arg = guard_op.getarg(0) - assert isinstance(arg, BoxVector) - size = arg.item_size + size = arg.bytesize temp = X86_64_XMM_SCRATCH_REG # self.mc.PXOR(temp, temp) @@ -65,7 +65,6 @@ def _guard_vector_false(self, guard_op, loc): arg = guard_op.getarg(0) - assert isinstance(arg, BoxVector) # # if the vector is not fully packed blend 1s if not arg.fully_packed(self.cpu.vector_register_size): @@ -204,6 +203,17 @@ # a second time -> every zero entry (corresponding to non zero # entries before) become ones self.mc.PCMPEQ(loc, temp, sizeloc.value) + # TODO + #self.flush_cc(rx86.Conditions['NZ'], resloc) + #loc = locs[0] + #if isinstance(loc, RegLoc): + # if loc.is_xmm: + # self._guard_vector_true(guard_op, loc) + # # XXX + # self.implement_guard(guard_token, 'NZ') + # return + #self.mc.TEST(loc, loc) + def genop_guard_vec_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): guard_opnum = guard_op.getopnum() @@ -618,11 +628,9 @@ def consider_vec_arith_unary(self, op): lhs = op.getarg(0) - assert isinstance(lhs, BoxVector) - size = lhs.item_size args = op.getarglist() res = self.xrm.force_result_in_reg(op, op.getarg(0), args) - self.perform(op, [res, imm(size)], res) + self.perform(op, [res, imm(lhs.bytesize)], res) consider_vec_float_neg = consider_vec_arith_unary consider_vec_float_abs = consider_vec_arith_unary @@ -637,15 +645,13 @@ def consider_vec_float_eq(self, op, guard_op): lhs = op.getarg(0) - assert isinstance(lhs, BoxVector) - size = lhs.item_size args = op.getarglist() lhsloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) rhsloc = self.make_sure_var_in_reg(op.getarg(1), args) if guard_op: - self.perform_with_guard(op, guard_op, [lhsloc, rhsloc, imm(size)], None) + self.perform_with_guard(op, guard_op, [lhsloc, rhsloc, imm(lhs.bytesize)], None) else: - self.perform(op, [lhsloc, rhsloc, imm(size)], lhsloc) + self.perform(op, [lhsloc, rhsloc, imm(lhs.bytesize)], lhsloc) consider_vec_float_ne = consider_vec_float_eq consider_vec_int_eq = consider_vec_float_eq @@ -681,16 +687,14 @@ assert isinstance(count, ConstInt) args = op.getarglist() srcloc = self.make_sure_var_in_reg(op.getarg(0), args) - if isinstance(op.result, BoxVector): + if op.is_vector(): resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) - assert isinstance(op.result, BoxVector) - size = op.result.getsize() + size = op.bytesize else: # unpack into iX box resloc = self.force_allocate_reg(op.result, args) arg = op.getarg(0) - assert isinstance(arg, BoxVector) - size = arg.getsize() + size = arg.bytesize residx = 0 args = op.getarglist() arglocs = [resloc, srcloc, imm(residx), imm(index.value), imm(count.value), imm(size)] @@ -726,16 +730,13 @@ assert size > 0 self.perform(op, [resloc, imm(size), imm(op.bytesize)], resloc) - def consider_vec_int_is_true(self, op, guard_op): + def consider_vec_int_is_true(self, op): args = op.getarglist() - resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) - sizearg = op.getarg(0) - assert isinstance(sizearg, BoxVector) - size = sizearg.getsize() - if guard_op is not None: - self.perform_with_guard(op, guard_op, [resloc,imm(size)], None) - else: - self.perform(op, [resloc,imm(size)], None) + #resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) + arg = op.getarg(0) + argloc = self.loc(arg) + resloc = self.force_allocate_reg_or_cc(op) + self.perform(op, [resloc,imm(size)], None) def _consider_vec(self, op): # pseudo instruction, needed to create a new variable diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -32,7 +32,6 @@ self.descrs.append(descr) assert descr not in self.leads_to self.leads_to[descr] = version - assert version.renamed_inputargs is not None def remove(self, descr): if descr in self.leads_to: @@ -90,12 +89,11 @@ create one instance and attach it to a guard descr. If not attached to a descriptor, it will not be compiled. """ - _attrs_ = ('label', 'operations', 'inputargs', 'renamed_inputargs') + _attrs_ = ('label', 'loop', 'inputargs') def __init__(self, loop): self.loop = loop self.inputargs = loop.label.getarglist() - self.renamed_inputargs = loop.label.getarglist() def setup_once(self, info): for op in self.loop.operations: diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -28,10 +28,11 @@ _repr_memo = CountingDict() is_info_class = False namespace = None - _attrs_ = ('datatype', 'bytesize', 'signed') + _attrs_ = ('datatype', 'bytesize', 'signed', 'count') datatype = '\x00' bytesize = -1 # -1 means the biggest size known to the machine signed = True + count = -1 def _get_hash_(self): return compute_identity_hash(self) @@ -121,15 +122,18 @@ return if self.is_primitive_array_access(): + from rpython.jit.backend.llsupport.descr import ArrayDescr descr = self.getdescr() if not we_are_translated(): from rpython.jit.backend.llgraph.runner import _getdescr descr = _getdescr(self) type = self.type - if descr.is_array_of_floats() or descr.concrete_type == 'f': + if descr.is_array_of_floats(): + type = 'f' + if isinstance(descr, ArrayDescr) and descr.getconcrete_type() == 'f': type = 'f' self.bytesize = descr.get_item_size_in_bytes() - self.sign = descr.is_item_signed() + self.signed = descr.is_item_signed() self.datatype = type elif self.opnum == rop.INT_SIGNEXT: from rpython.jit.metainterp import history @@ -166,6 +170,8 @@ self.setdatatype('r', INT_WORD, False) return self.setdatatype(arg.datatype, arg.bytesize, arg.signed) + if self.returns_bool_result(): + self.datatype = 'i' assert self.datatype != '\x00' #assert self.bytesize > 0 @@ -209,7 +215,6 @@ boolinverse = -1 vector = -1 # -1 means, no vector equivalent, -2 it is a vector statement casts = ('\x00', -1, '\x00', -1, -1) - count = -1 def getopnum(self): return self.opnum diff --git a/rpython/jit/metainterp/test/test_vector.py b/rpython/jit/metainterp/test/test_vector.py --- a/rpython/jit/metainterp/test/test_vector.py +++ b/rpython/jit/metainterp/test/test_vector.py @@ -157,6 +157,38 @@ res = self.meta_interp(f, [30]) assert res == f(30) == 128 + @py.test.mark.parametrize('func,init,insert,at,count,breaks', + # all + [(lambda x: not bool(x), 1.0, None, -1,32, False), + (lambda x: x == 0.0, 1.0, None, -1,33, False), + (lambda x: x == 0.0, 1.0, 0.0, 33,34, True), + # any + (lambda x: x != 0.0, 0.0, 1.0, 33,35, True), + (lambda x: x != 0.0, 0.0, 1.0, -1,36, False), + (lambda x: bool(x), 0.0, 1.0, 33,37, True), + (lambda x: bool(x), 0.0, 1.0, -1,38, False), + ]) + def test_bool_reduction(self, func, init, insert, at, count, breaks): + myjitdriver = JitDriver(greens = [], reds = 'auto', vectorize=True) + T = lltype.Array(rffi.DOUBLE, hints={'nolength': True}) + def f(d): + va = lltype.malloc(T, d, flavor='raw', zero=True) + for i in range(d): va[i] = init + if at != -1: + va[at] = insert + i = 0 ; nobreak = False + while i < d: + myjitdriver.jit_merge_point() + if func(va[i]): + break + i += 1 + else: + nobreak = True + lltype.free(va, flavor='raw') + return not nobreak + res = self.meta_interp(f, [count]) + assert res == f(count) == breaks + def test_sum(self): myjitdriver = JitDriver(greens = [], reds = 'auto', vectorize=True) T = lltype.Array(rffi.DOUBLE, hints={'nolength': True}) From noreply at buildbot.pypy.org Fri Sep 25 12:13:48 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 12:13:48 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: added more types to the bool reduction tests, assembler going forward, but still not correct results Message-ID: <20150925101348.4D06C1C012C@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79819:a7fd3e5a487c Date: 2015-09-25 12:13 +0200 http://bitbucket.org/pypy/pypy/changeset/a7fd3e5a487c/ Log: added more types to the bool reduction tests, assembler going forward, but still not correct results 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 @@ -829,6 +829,12 @@ bh_vec_int_eq = bh_vec_float_eq bh_vec_int_ne = bh_vec_float_ne + def bh_vec_int_is_true(self, vx, count): + return map(lambda x: bool(x), vx) + + def bh_vec_int_is_false(self, vx, count): + return map(lambda x: not bool(x), vx) + def bh_vec_int_xor(self, vx, vy, count): return [int(x) ^ int(y) for x,y in zip(vx,vy)] @@ -1075,22 +1081,22 @@ def execute_guard_early_exit(self, descr): pass - def _check_true(self, arg): + def _test_true(self, arg): if isinstance(arg, list): return all(arg) return arg - def _check_false(self, arg): + def _test_false(self, arg): if isinstance(arg, list): return any(arg) return arg def execute_guard_true(self, descr, arg): - if not self._check_true(arg): + if not self._test_true(arg): self.fail_guard(descr) def execute_guard_false(self, descr, arg): - if self._check_false(arg): + if self._test_false(arg): self.fail_guard(descr) def execute_guard_value(self, descr, arg1, arg2): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -584,7 +584,6 @@ name = "Bridge # %s" % (descr_number,) self.cpu.profile_agent.native_code_written(name, rawstart, fullsize) - print "bridge pos", hex(startpos+rawstart), hex(rawstart+bridgestartpos), startpos return AsmInfo(ops_offset, startpos + rawstart, codeendpos - startpos, rawstart+bridgestartpos) def stitch_bridge(self, faildescr, target): @@ -639,7 +638,6 @@ rawstart = self.materialize_loop(looptoken) # update the jump to the real trace self._patch_jump_for_descr(rawstart + offset, asminfo.rawstart) - print faildescr, "=>", hex(asminfo.rawstart) # update the guard to jump right to this custom piece of assembler self.patch_jump_for_descr(faildescr, rawstart) @@ -1069,6 +1067,8 @@ if result_loc is ebp: self.guard_success_cc = cond else: + if result_loc.is_xmm: + return rl = result_loc.lowest8bits() self.mc.SET_ir(cond, rl.value) self.mc.MOVZX8_rr(result_loc.value, rl.value) @@ -1663,14 +1663,6 @@ def genop_guard_guard_false(self, guard_op, guard_token, locs, resloc): self.guard_success_cc = rx86.invert_condition(self.guard_success_cc) - # TODO loc = locs[0] - #if isinstance(loc, RegLoc): - # if loc.is_xmm: - # self._guard_vector_false(guard_op, loc) - # # XXX - # self.implement_guard(guard_token, 'NZ') - # return - #self.mc.TEST(loc, loc) self.implement_guard(guard_token) genop_guard_guard_isnull = genop_guard_guard_false diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -400,7 +400,8 @@ def load_condition_into_cc(self, box): if self.assembler.guard_success_cc == rx86.cond_none: - self.assembler.test_location(self.loc(box)) + if not box.is_vector(): + self.assembler.test_location(self.loc(box)) self.assembler.guard_success_cc = rx86.Conditions['NZ'] def _consider_guard_cc(self, op): diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -14,6 +14,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.lltypesystem import lltype +from rpython.jit.backend.x86 import rx86 # duplicated for easy migration, def in assembler.py as well # DUP START @@ -33,6 +34,35 @@ class VectorAssemblerMixin(object): _mixin_ = True + def guard_vector(self, guard_op, loc, true): + arg = guard_op.getarg(0) + size = arg.bytesize + temp = X86_64_XMM_SCRATCH_REG + load = arg.bytesize * arg.count - self.cpu.vector_register_size + assert load <= 0 + if true: + self.mc.PXOR(temp, temp) + # if the vector is not fully packed blend 1s + if load < 0: + self.mc.PCMPEQQ(temp, temp) # fill with ones + self._blend_unused_slots(loc, arg, temp) + # reset to zeros + self.mc.PXOR(temp, temp) + + # cmp with zeros (in temp) creates ones at each slot where it is zero + self.mc.PCMPEQ(loc, temp, size) + # temp converted to ones + self.mc.PCMPEQQ(temp, temp) + # test if all slots are zero + self.mc.PTEST(loc, temp) + else: + # if the vector is not fully packed blend 1s + if load < 0: + temp = X86_64_XMM_SCRATCH_REG + self.mc.PXOR(temp, temp) + self._blend_unused_slots(loc, arg, temp) + self.mc.PTEST(loc, loc) + def _blend_unused_slots(self, loc, arg, temp): select = 0 bits_used = (arg.item_count * arg.item_size * 8) @@ -42,38 +72,6 @@ index += 1 self.mc.PBLENDW_xxi(loc.value, temp.value, select) - def _guard_vector_true(self, guard_op, loc, zero=False): - return - arg = guard_op.getarg(0) - size = arg.bytesize - temp = X86_64_XMM_SCRATCH_REG - # - self.mc.PXOR(temp, temp) - # if the vector is not fully packed blend 1s - if not arg.fully_packed(self.cpu.vector_register_size): - self.mc.PCMPEQQ(temp, temp) # fill with ones - self._blend_unused_slots(loc, arg, temp) - # reset to zeros - self.mc.PXOR(temp, temp) - - # cmp with zeros (in temp) creates ones at each slot where it is zero - self.mc.PCMPEQ(loc, temp, size) - # temp converted to ones - self.mc.PCMPEQQ(temp, temp) - # test if all slots are zero - self.mc.PTEST(loc, temp) - - def _guard_vector_false(self, guard_op, loc): - arg = guard_op.getarg(0) - # - # if the vector is not fully packed blend 1s - if not arg.fully_packed(self.cpu.vector_register_size): - temp = X86_64_XMM_SCRATCH_REG - self.mc.PXOR(temp, temp) - self._blend_unused_slots(loc, arg, temp) - # - self.mc.PTEST(loc, loc) - def _accum_update_at_exit(self, fail_locs, fail_args, faildescr, regalloc): """ If accumulation is done in this loop, at the guard exit some vector registers must be adjusted to yield the correct value @@ -203,26 +201,16 @@ # a second time -> every zero entry (corresponding to non zero # entries before) become ones self.mc.PCMPEQ(loc, temp, sizeloc.value) - # TODO - #self.flush_cc(rx86.Conditions['NZ'], resloc) - #loc = locs[0] - #if isinstance(loc, RegLoc): - # if loc.is_xmm: - # self._guard_vector_true(guard_op, loc) - # # XXX - # self.implement_guard(guard_token, 'NZ') - # return - #self.mc.TEST(loc, loc) + self.flush_cc(rx86.Conditions['NZ'], resloc) - - def genop_guard_vec_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): - guard_opnum = guard_op.getopnum() - if guard_opnum == rop.GUARD_TRUE: - self._guard_vector_true(op, arglocs[0]) - self.implement_guard(guard_token, 'NZ') - else: - self._guard_vector_false(op, arglocs[0]) - self.implement_guard(guard_token, 'NZ') + #def genop_guard_vec_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): + # guard_opnum = guard_op.getopnum() + # if guard_opnum == rop.GUARD_TRUE: + # self._guard_vector_true(op, arglocs[0]) + # self.implement_guard(guard_token, 'NZ') + # else: + # self._guard_vector_false(op, arglocs[0]) + # self.implement_guard(guard_token, 'NZ') def genop_vec_int_mul(self, op, arglocs, resloc): loc0, loc1, itemsize_loc = arglocs @@ -233,9 +221,7 @@ self.mc.PMULLD(loc0, loc1) else: # NOTE see http://stackoverflow.com/questions/8866973/can-long-integer-routines-benefit-from-sse/8867025#8867025 - # There is no 64x64 bit packed mul and I did not find one - # for 8 bit either. It is questionable if it gives any benefit - # for 8 bit. + # There is no 64x64 bit packed mul. For 8 bit either. It is questionable if it gives any benefit? not_implemented("int8/64 mul") def genop_vec_int_add(self, op, arglocs, resloc): @@ -311,6 +297,7 @@ self.mc.XORPS(src, heap(self.single_float_const_neg_addr)) elif size == 8: self.mc.XORPD(src, heap(self.float_const_neg_addr)) + self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_float_eq(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -319,6 +306,7 @@ self.mc.CMPPS_xxi(resloc.value, rhsloc.value, 0) # 0 means equal else: self.mc.CMPPD_xxi(resloc.value, rhsloc.value, 0) + self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_float_ne(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -328,11 +316,13 @@ self.mc.CMPPS_xxi(resloc.value, rhsloc.value, 1 << 2) else: self.mc.CMPPD_xxi(resloc.value, rhsloc.value, 1 << 2) + self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_int_eq(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs size = sizeloc.value self.mc.PCMPEQ(resloc, rhsloc, size) + self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_int_ne(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -346,6 +336,7 @@ # 11 11 11 11 # ----------- pxor # 00 11 00 00 + self.flush_cc(rx86.Conditions['NZ'], resloc) def gen_cmp(func): """ The requirement for func is that it must return one bits for each @@ -362,10 +353,9 @@ self.mc.PCMPEQ(lhsloc, temp, size) # compare self.mc.PCMPEQQ(temp, temp) # set all bits to 1 self.mc.PTEST(lhsloc, temp) - self.implement_guard(guard_token, 'NZ') else: self.mc.PTEST(lhsloc, lhsloc) - self.implement_guard(guard_token, 'NZ') + self.flush_cc(x86.Conditions['NZ'], lhsloc) return generate_assembler genop_guard_vec_float_eq = gen_cmp(genop_vec_float_eq) @@ -643,15 +633,13 @@ result = self.xrm.force_result_in_reg(op, op.getarg(0), args) self.perform(op, [source, imm(lhs.bytesize)], result) - def consider_vec_float_eq(self, op, guard_op): + def consider_vec_float_eq(self, op): lhs = op.getarg(0) args = op.getarglist() lhsloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) rhsloc = self.make_sure_var_in_reg(op.getarg(1), args) - if guard_op: - self.perform_with_guard(op, guard_op, [lhsloc, rhsloc, imm(lhs.bytesize)], None) - else: - self.perform(op, [lhsloc, rhsloc, imm(lhs.bytesize)], lhsloc) + resloc = self.force_allocate_reg_or_cc(op) + self.perform(op, [lhsloc, rhsloc, imm(lhs.bytesize)], lhsloc) consider_vec_float_ne = consider_vec_float_eq consider_vec_int_eq = consider_vec_float_eq diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -195,7 +195,6 @@ _attrs_ = ('_forwarded',) _forwarded = None # either another resop or OptInfo - def get_forwarded(self): return self._forwarded @@ -1031,8 +1030,8 @@ 'VEC_FLOAT_NEG/1/f', 'VEC_FLOAT_ABS/1/f', '_VEC_ARITHMETIC_LAST', - 'VEC_FLOAT_EQ/2b/f', - 'VEC_FLOAT_NE/2b/f', + 'VEC_FLOAT_EQ/2b/i', + 'VEC_FLOAT_NE/2b/i', 'VEC_INT_IS_TRUE/1b/i', 'VEC_INT_NE/2b/i', 'VEC_INT_EQ/2b/i', diff --git a/rpython/jit/metainterp/test/test_vector.py b/rpython/jit/metainterp/test/test_vector.py --- a/rpython/jit/metainterp/test/test_vector.py +++ b/rpython/jit/metainterp/test/test_vector.py @@ -157,20 +157,31 @@ res = self.meta_interp(f, [30]) assert res == f(30) == 128 - @py.test.mark.parametrize('func,init,insert,at,count,breaks', + @py.test.mark.parametrize('type,func,init,insert,at,count,breaks', # all - [(lambda x: not bool(x), 1.0, None, -1,32, False), - (lambda x: x == 0.0, 1.0, None, -1,33, False), - (lambda x: x == 0.0, 1.0, 0.0, 33,34, True), + [(rffi.DOUBLE, lambda x: not bool(x), 1.0, None, -1,32, False), + (rffi.DOUBLE, lambda x: x == 0.0, 1.0, None, -1,33, False), + (rffi.DOUBLE, lambda x: x == 0.0, 1.0, 0.0, 33,34, True), + (lltype.Signed, lambda x: not bool(x), 1, None, -1,32, False), + (lltype.Signed, lambda x: x == 0, 1, None, -1,33, False), + (lltype.Signed, lambda x: x == 0, 1, 0, 33,34, True), # any - (lambda x: x != 0.0, 0.0, 1.0, 33,35, True), - (lambda x: x != 0.0, 0.0, 1.0, -1,36, False), - (lambda x: bool(x), 0.0, 1.0, 33,37, True), - (lambda x: bool(x), 0.0, 1.0, -1,38, False), + (rffi.DOUBLE, lambda x: x != 0.0, 0.0, 1.0, 33,35, True), + (rffi.DOUBLE, lambda x: x != 0.0, 0.0, 1.0, -1,36, False), + (rffi.DOUBLE, lambda x: bool(x), 0.0, 1.0, 33,37, True), + (rffi.DOUBLE, lambda x: bool(x), 0.0, 1.0, -1,38, False), + (lltype.Signed, lambda x: x != 0, 0, 1, 33,35, True), + (lltype.Signed, lambda x: x != 0, 0, 1, -1,36, False), + (lltype.Signed, lambda x: bool(x), 0, 1, 33,37, True), + (lltype.Signed, lambda x: bool(x), 0, 1, -1,38, False), + (rffi.INT, lambda x: intmask(x) != 0, rffi.r_int(0), rffi.r_int(1), 33,35, True), + (rffi.INT, lambda x: intmask(x) != 0, rffi.r_int(0), rffi.r_int(1), -1,36, False), + (rffi.INT, lambda x: bool(intmask(x)), rffi.r_int(0), rffi.r_int(1), 33,37, True), + (rffi.INT, lambda x: bool(intmask(x)), rffi.r_int(0), rffi.r_int(1), -1,38, False), ]) - def test_bool_reduction(self, func, init, insert, at, count, breaks): + def test_bool_reduction(self, type, func, init, insert, at, count, breaks): myjitdriver = JitDriver(greens = [], reds = 'auto', vectorize=True) - T = lltype.Array(rffi.DOUBLE, hints={'nolength': True}) + T = lltype.Array(type, hints={'nolength': True}) def f(d): va = lltype.malloc(T, d, flavor='raw', zero=True) for i in range(d): va[i] = init From noreply at buildbot.pypy.org Fri Sep 25 14:13:51 2015 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 25 Sep 2015 14:13:51 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: debug prints Message-ID: <20150925121351.7FBCA1C012C@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79820:16777999b7b7 Date: 2015-09-25 14:14 +0200 http://bitbucket.org/pypy/pypy/changeset/16777999b7b7/ Log: debug prints 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 @@ -9,6 +9,7 @@ from rpython.jit.metainterp.optimizeopt import info from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.objectmodel import specialize, we_are_translated +from rpython.rlib.debug import debug_print @@ -499,6 +500,8 @@ def propagate_all_forward(self, inputargs, ops, call_pure_results=None, rename_inputargs=True, flush=True, origin_jitcode=None, origin_pc=0): + if origin_jitcode is not None: + debug_print("looking for guard at %s %d" % (origin_jitcode.name, origin_pc)) self.origin_jitcode = origin_jitcode self.origin_pc = origin_pc if rename_inputargs: 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 @@ -2471,6 +2471,10 @@ def prepare_resume_from_failure(self, deadframe, resumedescr): exception = self.cpu.grab_exc_value(deadframe) + if isinstance(resumedescr, compile.ResumeGuardDescr): + name = resumedescr.rd_frame_info_list.jitcode.name + pc = resumedescr.rd_frame_info_list.pc + debug_print("resuming at %s %d" % (name, pc)) if isinstance(resumedescr, compile.ResumeGuardExcDescr): if exception: self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, From noreply at buildbot.pypy.org Fri Sep 25 15:42:51 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 15:42:51 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: guard true/false for vectors work for the new test cases Message-ID: <20150925134251.C23971C135E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79821:b87eaf3540b3 Date: 2015-09-25 14:51 +0200 http://bitbucket.org/pypy/pypy/changeset/b87eaf3540b3/ Log: guard true/false for vectors work for the new test cases diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -400,18 +400,25 @@ def load_condition_into_cc(self, box): if self.assembler.guard_success_cc == rx86.cond_none: - if not box.is_vector(): - self.assembler.test_location(self.loc(box)) + self.assembler.test_location(self.loc(box)) self.assembler.guard_success_cc = rx86.Conditions['NZ'] - def _consider_guard_cc(self, op): - self.load_condition_into_cc(op.getarg(0)) - self.perform_guard(op, [], None) - consider_guard_true = _consider_guard_cc - consider_guard_false = _consider_guard_cc - consider_guard_nonnull = _consider_guard_cc - consider_guard_isnull = _consider_guard_cc + def _consider_guard_cc(true): + def function(self, op): + arg = op.getarg(0) + if arg.is_vector(): + loc = self.loc(arg) + self.assembler.guard_vector(op, self.loc(arg), true) + else: + self.load_condition_into_cc(arg) + self.perform_guard(op, [], None) + return function + + consider_guard_true = _consider_guard_cc(True) + consider_guard_false = _consider_guard_cc(False) + consider_guard_nonnull = _consider_guard_cc(True) + consider_guard_isnull = _consider_guard_cc(False) def consider_finish(self, op): # the frame is in ebp, but we have to point where in the frame is diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -55,6 +55,7 @@ self.mc.PCMPEQQ(temp, temp) # test if all slots are zero self.mc.PTEST(loc, temp) + self.guard_success_cc = rx86.Conditions['Z'] else: # if the vector is not fully packed blend 1s if load < 0: @@ -62,6 +63,7 @@ self.mc.PXOR(temp, temp) self._blend_unused_slots(loc, arg, temp) self.mc.PTEST(loc, loc) + self.guard_success_cc = rx86.Conditions['NZ'] def _blend_unused_slots(self, loc, arg, temp): select = 0 @@ -201,16 +203,6 @@ # a second time -> every zero entry (corresponding to non zero # entries before) become ones self.mc.PCMPEQ(loc, temp, sizeloc.value) - self.flush_cc(rx86.Conditions['NZ'], resloc) - - #def genop_guard_vec_int_is_true(self, op, guard_op, guard_token, arglocs, resloc): - # guard_opnum = guard_op.getopnum() - # if guard_opnum == rop.GUARD_TRUE: - # self._guard_vector_true(op, arglocs[0]) - # self.implement_guard(guard_token, 'NZ') - # else: - # self._guard_vector_false(op, arglocs[0]) - # self.implement_guard(guard_token, 'NZ') def genop_vec_int_mul(self, op, arglocs, resloc): loc0, loc1, itemsize_loc = arglocs @@ -297,7 +289,6 @@ self.mc.XORPS(src, heap(self.single_float_const_neg_addr)) elif size == 8: self.mc.XORPD(src, heap(self.float_const_neg_addr)) - self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_float_eq(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -306,7 +297,6 @@ self.mc.CMPPS_xxi(resloc.value, rhsloc.value, 0) # 0 means equal else: self.mc.CMPPD_xxi(resloc.value, rhsloc.value, 0) - self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_float_ne(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -316,13 +306,11 @@ self.mc.CMPPS_xxi(resloc.value, rhsloc.value, 1 << 2) else: self.mc.CMPPD_xxi(resloc.value, rhsloc.value, 1 << 2) - self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_int_eq(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs size = sizeloc.value self.mc.PCMPEQ(resloc, rhsloc, size) - self.flush_cc(rx86.Conditions['NZ'], resloc) def genop_vec_int_ne(self, op, arglocs, resloc): _, rhsloc, sizeloc = arglocs @@ -336,7 +324,6 @@ # 11 11 11 11 # ----------- pxor # 00 11 00 00 - self.flush_cc(rx86.Conditions['NZ'], resloc) def gen_cmp(func): """ The requirement for func is that it must return one bits for each @@ -720,11 +707,10 @@ def consider_vec_int_is_true(self, op): args = op.getarglist() - #resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) arg = op.getarg(0) argloc = self.loc(arg) - resloc = self.force_allocate_reg_or_cc(op) - self.perform(op, [resloc,imm(size)], None) + resloc = self.xrm.force_result_in_reg(op, arg, args) + self.perform(op, [resloc,imm(arg.bytesize)], None) def _consider_vec(self, op): # pseudo instruction, needed to create a new variable diff --git a/rpython/jit/metainterp/test/test_vector.py b/rpython/jit/metainterp/test/test_vector.py --- a/rpython/jit/metainterp/test/test_vector.py +++ b/rpython/jit/metainterp/test/test_vector.py @@ -162,6 +162,7 @@ [(rffi.DOUBLE, lambda x: not bool(x), 1.0, None, -1,32, False), (rffi.DOUBLE, lambda x: x == 0.0, 1.0, None, -1,33, False), (rffi.DOUBLE, lambda x: x == 0.0, 1.0, 0.0, 33,34, True), + (rffi.DOUBLE, lambda x: x == 0.0, 1.0, 0.1, 4,34, False), (lltype.Signed, lambda x: not bool(x), 1, None, -1,32, False), (lltype.Signed, lambda x: x == 0, 1, None, -1,33, False), (lltype.Signed, lambda x: x == 0, 1, 0, 33,34, True), From noreply at buildbot.pypy.org Fri Sep 25 15:42:54 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 15:42:54 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: checked for accidental removal of code, or failed merged lines Message-ID: <20150925134254.17DB01C135E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79822:a856dc8ba36f Date: 2015-09-25 15:30 +0200 http://bitbucket.org/pypy/pypy/changeset/a856dc8ba36f/ Log: checked for accidental removal of code, or failed merged lines diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -336,7 +336,7 @@ def cast_int_to_ptr(self, x, TYPE): return rffi.cast(TYPE, x) - def sizeof(self, S, vtable): + def sizeof(self, S, vtable=lltype.nullptr(rclass.OBJECT_VTABLE)): return get_size_descr(self.gc_ll_descr, S, vtable) def fielddescrof(self, STRUCT, fieldname): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -650,7 +650,6 @@ startpos = self.mc.get_relative_pos() self.store_info_on_descr(startpos, tok) else: - # TODO regalloc.position = tok.position tok.pos_recovery_stub = self.generate_quick_failure(tok, regalloc) if WORD == 8 and len(self.pending_memoryerror_trampoline_from) > 0: self.error_trampoline_64 = self.generate_propagate_error_64() @@ -1067,8 +1066,6 @@ if result_loc is ebp: self.guard_success_cc = cond else: - if result_loc.is_xmm: - return rl = result_loc.lowest8bits() self.mc.SET_ir(cond, rl.value) self.mc.MOVZX8_rr(result_loc.value, rl.value) @@ -1789,13 +1786,12 @@ self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) - def genop_guard_guard_gc_type(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_gc_type(self, guard_op, guard_token, locs, ign): self._cmp_guard_gc_type(locs[0], locs[1]) - self.implement_guard(guard_token, 'NE') + self.guard_success_cc = rx86.Conditions['E'] + self.implement_guard(guard_token) - def genop_guard_guard_is_object(self, ign_1, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_is_object(self, guard_op, guard_token, locs, ign): assert self.cpu.supports_guard_gc_type [loc_object, loc_typeid] = locs # idea: read the typeid, fetch the field 'infobits' from the big @@ -1811,12 +1807,12 @@ self.cpu.gc_ll_descr.get_translated_info_for_guard_is_object()) loc_infobits = addr_add(imm(base_type_info), loc_typeid, scale=shift_by, offset=infobits_offset) - self.mc.TEST(loc_infobits, imm(IS_OBJECT_FLAG)) + self.mc.TEST8(loc_infobits, imm(IS_OBJECT_FLAG)) # - self.implement_guard(guard_token, 'Z') + self.guard_success_cc = rx86.Conditions['NZ'] + self.implement_guard(guard_token) - def genop_guard_guard_subclass(self, op, guard_op, - guard_token, locs, ign_2): + def genop_guard_guard_subclass(self, guard_op, guard_token, locs, ign): assert self.cpu.supports_guard_gc_type [loc_object, loc_check_against_class, loc_tmp] = locs assert isinstance(loc_object, RegLoc) @@ -1849,8 +1845,9 @@ # check by doing the unsigned comparison (tmp - min) < (max - min) self.mc.SUB_ri(loc_tmp.value, check_min) self.mc.CMP_ri(loc_tmp.value, check_max - check_min) - # the guard fails if we get a "not below" result - self.implement_guard(guard_token, 'NB') + # the guard passes if we get a result of "below" + self.guard_success_cc = rx86.Conditions['B'] + self.implement_guard(guard_token) def implement_guard_recovery(self, guard_opnum, faildescr, failargs, fail_locs, frame_depth): @@ -2078,9 +2075,8 @@ self.guard_success_cc = rx86.Conditions['E'] self.implement_guard(guard_token) - def _genop_call_may_force(self, op, guard_op, guard_token, - arglocs, result_loc): - self._store_force_index(guard_op) + def _genop_call_may_force(self, op, arglocs, result_loc): + self._store_force_index(self._find_nearby_operation(+1)) self._genop_call(op, arglocs, result_loc) genop_call_may_force_i = _genop_call_may_force genop_call_may_force_r = _genop_call_may_force @@ -2332,6 +2328,7 @@ self.mc.J_il8(rx86.invert_condition(self.guard_success_cc), 0) # patched later jmp_adr = self.mc.get_relative_pos() + self.guard_success_cc = rx86.cond_none # self.push_gcmap(self.mc, gcmap, store=True) # diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -725,7 +725,7 @@ args = [op.getarg(1), op.getarg(2)] loc1 = self.load_xmm_aligned_16_bytes(args[0]) loc2 = self.load_xmm_aligned_16_bytes(args[1], args) - tmpxvar = TempBox() + tmpxvar = TempVar() loc3 = self.xrm.force_allocate_reg(tmpxvar, args) self.xrm.possibly_free_var(tmpxvar) loc0 = self.rm.force_allocate_reg(op, need_lower_byte=True) @@ -822,7 +822,7 @@ resloc = self.rm.after_call(op) else: resloc = None - self.perform(op, arglocs, resloc) + self.perform(op, arglocs, resloc) def _consider_call(self, op, guard_not_forced=False, first_arg_index=1): calldescr = op.getdescr() diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -325,32 +325,6 @@ # ----------- pxor # 00 11 00 00 - def gen_cmp(func): - """ The requirement for func is that it must return one bits for each - entry that matches the query, zero otherwise. - """ - def generate_assembler(self, op, guard_op, guard_token, arglocs, resloc): - lhsloc, rhsloc, sizeloc = arglocs - size = sizeloc.value - func(self, op, arglocs, lhsloc) - guard_opnum = guard_op.getopnum() - if guard_opnum == rop.GUARD_TRUE: - temp = X86_64_XMM_SCRATCH_REG - self.mc.PXOR(temp, temp) # set all to zero - self.mc.PCMPEQ(lhsloc, temp, size) # compare - self.mc.PCMPEQQ(temp, temp) # set all bits to 1 - self.mc.PTEST(lhsloc, temp) - else: - self.mc.PTEST(lhsloc, lhsloc) - self.flush_cc(x86.Conditions['NZ'], lhsloc) - return generate_assembler - - genop_guard_vec_float_eq = gen_cmp(genop_vec_float_eq) - genop_guard_vec_float_ne = gen_cmp(genop_vec_float_ne) - genop_guard_vec_int_eq = gen_cmp(genop_vec_int_eq) - genop_guard_vec_int_ne = gen_cmp(genop_vec_int_ne) - del gen_cmp - def genop_vec_int_signext(self, op, arglocs, resloc): srcloc, sizeloc, tosizeloc = arglocs size = sizeloc.value diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -24,7 +24,7 @@ class CompileData(object): memo = None - + def forget_optimization_info(self): for arg in self.start_label.getarglist(): arg.set_forwarded(None) @@ -261,7 +261,7 @@ del enable_opts['unroll'] ops = history.operations[start:] - if 'unroll' not in enable_opts: + if 'unroll' not in enable_opts or not metainterp.cpu.supports_guard_gc_type: return compile_simple_loop(metainterp, greenkey, start, inputargs, ops, jumpargs, enable_opts) jitcell_token = make_jitcell_token(jitdriver_sd) @@ -358,8 +358,7 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - loop_data, - metainterp.box_names_memo) + loop_data) except InvalidLoop: # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token) @@ -682,7 +681,7 @@ _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals', 'rd_frame_info_list', 'rd_pendingfields', 'rd_accum_list', 'status') - + rd_numb = lltype.nullptr(NUMBERING) rd_count = 0 rd_consts = None @@ -890,12 +889,6 @@ class ResumeAtPositionDescr(ResumeGuardDescr): guard_opnum = rop.GUARD_FUTURE_CONDITION -class ResumeAtLoopHeaderDescr(ResumeGuardDescr): - guard_opnum = rop.GUARD_EARLY_EXIT - - def exits_early(self): - return True - class CompileLoopVersionDescr(ResumeGuardDescr): guard_opnum = rop.GUARD_EARLY_EXIT @@ -1002,8 +995,6 @@ resumedescr = ResumeGuardNotInvalidated() elif opnum == rop.GUARD_FUTURE_CONDITION: resumedescr = ResumeAtPositionDescr() - elif opnum == rop.GUARD_EARLY_EXIT: - resumedescr = ResumeAtLoopHeaderDescr() elif opnum == rop.GUARD_VALUE: resumedescr = ResumeGuardValueDescr() elif opnum == rop.GUARD_NONNULL: @@ -1067,7 +1058,6 @@ # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. - metainterp_sd = metainterp.staticdata jitdriver_sd = metainterp.jitdriver_sd if isinstance(resumekey, ResumeAtPositionDescr): @@ -1095,6 +1085,7 @@ info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) except InvalidLoop: + #pdb.post_mortem(sys.exc_info()[2]) debug_print("compile_new_bridge: got an InvalidLoop") # XXX I am fairly convinced that optimize_bridge cannot actually raise # InvalidLoop diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -187,7 +187,7 @@ else: assert lltype.typeOf(value) == llmemory.GCREF return ConstPtr(value) - + class MissingValue(object): "NOT_RPYTHON" @@ -808,14 +808,12 @@ check['getfield_gc_pure_i'] = check['getfield_gc_pure_r'] = check['getfield_gc_pure_f'] = 0 if 'getarrayitem_gc_pure' in check: assert check.pop('getarrayitem_gc_pure') == 0 - check['getarrayitem_gc_pure_i'] = check['getarrayitem_gc_pure_r'] = check['getarrayitem_gc_pure_f'] = 0 + check['getarrayitem_gc_pure_i'] = check['getarrayitem_gc_pure_r'] = check['getarrayitem_gc_pure_f'] = 0 if 'getarrayitem_gc' in check: assert check.pop('getarrayitem_gc') == 0 check['getarrayitem_gc_i'] = check['getarrayitem_gc_r'] = check['getarrayitem_gc_f'] = 0 for loop in self.get_all_loops(): insns = loop.summary(adding_insns=insns, omit_finish=omit_finish) - if 'guard_early_exit' in insns: - del insns['guard_early_exit'] return self._check_insns(insns, expected, check) def _check_insns(self, insns, expected, check): diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -273,7 +273,7 @@ r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop( op) raise InvalidLoop('A GUARD_VALUE (%s) ' - 'to always fail' % r) + 'was proven to always fail' % r) return if emit_operation: diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -1011,7 +1011,7 @@ 'CAST_INT_TO_FLOAT/1/f', # need some messy code in the backend 'CAST_FLOAT_TO_SINGLEFLOAT/1/i', 'CAST_SINGLEFLOAT_TO_FLOAT/1/f', - 'CONVERT_FLOAT_BYTES_TO_LONGLONG/1/i', + 'CONVERT_FLOAT_BYTES_TO_LONGLONG/1/' + ('i' if longlong.is_64_bit else 'f'), 'CONVERT_LONGLONG_BYTES_TO_FLOAT/1/f', # # vector operations From noreply at buildbot.pypy.org Fri Sep 25 15:42:56 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 15:42:56 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: translation issues resolved, should compile now Message-ID: <20150925134256.3BBE51C135E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79823:a79a0fc8b3ea Date: 2015-09-25 15:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a79a0fc8b3ea/ Log: translation issues resolved, should compile now diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -67,7 +67,7 @@ def _blend_unused_slots(self, loc, arg, temp): select = 0 - bits_used = (arg.item_count * arg.item_size * 8) + bits_used = (arg.count * arg.bytesize * 8) index = bits_used // 16 while index < 8: select |= (1 << index) @@ -637,11 +637,11 @@ args = op.getarglist() srcloc = self.make_sure_var_in_reg(op.getarg(0), args) if op.is_vector(): - resloc = self.xrm.force_result_in_reg(op.result, op.getarg(0), args) + resloc = self.xrm.force_result_in_reg(op, op.getarg(0), args) size = op.bytesize else: # unpack into iX box - resloc = self.force_allocate_reg(op.result, args) + resloc = self.force_allocate_reg(op, args) arg = op.getarg(0) size = arg.bytesize residx = 0 diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -189,8 +189,7 @@ def exits_early(self): if self.op.is_guard(): descr = self.op.getdescr() - return isinstance(descr, compile.ResumeAtLoopHeaderDescr) or \ - isinstance(descr, compile.CompileLoopVersionDescr) + return isinstance(descr, compile.CompileLoopVersionDescr) return False def loads_from_complex_object(self): @@ -724,8 +723,7 @@ self.guard_argument_protection(guard_node, tracker) # descr = guard_op.getdescr() - if isinstance(descr, compile.ResumeAtLoopHeaderDescr) or \ - isinstance(descr, compile.CompileLoopVersionDescr): + if isinstance(descr, compile.CompileLoopVersionDescr): return # handle fail args if guard_op.getfailargs(): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -6,7 +6,6 @@ from rpython.jit.metainterp.history import TargetToken, JitCellToken, TreeLoop from rpython.jit.metainterp.optimizeopt.dependency import (DependencyGraph, Dependency, IndexVar, MemoryRef, Node) -from rpython.jit.metainterp.compile import ResumeAtLoopHeaderDescr from rpython.jit.metainterp.optimizeopt.vector import VectorLoop from rpython.jit.metainterp.resoperation import rop, ResOperation from rpython.jit.backend.llgraph.runner import ArrayDescr @@ -55,10 +54,6 @@ jump = loop.operations[-1] loop = VectorLoop(label, loop.operations[0:-1], jump) loop.jump.setdescr(token) - # TODO - for op in loop.operations: - if op.getopnum() == rop.GUARD_EARLY_EXIT and op.getdescr() is None: - op.setdescr(ResumeAtLoopHeaderDescr()) return loop def parse_trace(self, source, inc_label_jump=True, pargs=2, iargs=10, diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -97,12 +97,6 @@ unroll_factor = opt.get_unroll_count(ARCH_VEC_REG_SIZE) print "" print "unroll factor: ", unroll_factor, opt.smallest_type_bytes - # TODO if opt.loop.find_first_index(rop.GUARD_EARLY_EXIT) == -1: - # idx = loop.find_first_index(rop.LABEL) - # guard = ResOperation(rop.GUARD_EARLY_EXIT, [], None) - # guard.setfailargs([]) - # guard.setdescr(compile.ResumeAtLoopHeaderDescr()) - # loop.operations.insert(idx+1, guard) self.show_dot_graph(DependencyGraph(loop), "original_" + self.test_name) graph = opt.analyse_index_calculations(loop) if graph is not None: diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -11,8 +11,8 @@ from rpython.jit.metainterp.resume import Snapshot from rpython.jit.metainterp.jitexc import NotAVectorizeableLoop, NotAProfitableLoop #from rpython.jit.metainterp.optimizeopt.unroll import optimize_unroll -from rpython.jit.metainterp.compile import (ResumeAtLoopHeaderDescr, - CompileLoopVersionDescr, invent_fail_descr_for_op, ResumeGuardDescr) +from rpython.jit.metainterp.compile import (CompileLoopVersionDescr, + invent_fail_descr_for_op, ResumeGuardDescr) from rpython.jit.metainterp.history import (INT, FLOAT, VECTOR, ConstInt, ConstFloat, TargetToken, JitCellToken, AbstractFailDescr) from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization diff --git a/rpython/jit/metainterp/optimizeopt/version.py b/rpython/jit/metainterp/optimizeopt/version.py --- a/rpython/jit/metainterp/optimizeopt/version.py +++ b/rpython/jit/metainterp/optimizeopt/version.py @@ -7,7 +7,8 @@ class LoopVersionInfo(BasicLoopInfo): def __init__(self, info): - self.target_token = info.target_token + assert isinstance(info, BasicLoopInfo) + #self.target_token = info.target_token self.label_op = info.label_op self.extra_same_as = info.extra_same_as self.quasi_immutable_deps = info.quasi_immutable_deps @@ -81,7 +82,7 @@ param = compiled[version] cpu.stitch_bridge(descr, param) - self.versions = None # dismiss versions + self.versions = [] # dismiss versions class LoopVersion(object): From noreply at buildbot.pypy.org Fri Sep 25 16:37:58 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 16:37:58 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move: Give up, bad approach Message-ID: <20150925143758.606D21C1DFF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move Changeset: r79824:39acaa1aae45 Date: 2015-09-25 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/39acaa1aae45/ Log: Give up, bad approach diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -18,6 +18,8 @@ sizeofaddr = llmemory.sizeof(llmemory.Address) +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# CALL THIS! def complete_destrptr(gctransformer): translator = gctransformer.translator mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -156,10 +156,12 @@ else: # switch to this stacklet print "switch to", n + print "self = %r" % (self,) h = task.h task.h = runner.sthread.get_null_handle() h = runner.sthread.switch(h) + print "self = %r" % (self,) print "back in self.n = %d, coming from %d" % (self.n, runner.comefrom) assert runner.nextstep == runner.status From noreply at buildbot.pypy.org Fri Sep 25 16:38:00 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 16:38:00 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move-2: A branch to fix issue #2141 (2nd try): after the fix for issue Message-ID: <20150925143800.750891C1DFF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move-2 Changeset: r79825:5f88acec0724 Date: 2015-09-25 11:08 +0200 http://bitbucket.org/pypy/pypy/changeset/5f88acec0724/ Log: A branch to fix issue #2141 (2nd try): after the fix for issue #2017, one good optimization in the JIT doesn't actually work if we are running more than MAX-1 threads (19). I will try to revert that patch and fix it differently inside _stacklet_shadowstack.py. From noreply at buildbot.pypy.org Fri Sep 25 16:38:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 16:38:02 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move-2: Kill and simplify a lot of code Message-ID: <20150925143802.966561C1DFF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move-2 Changeset: r79826:3bf64dd0bbef Date: 2015-09-25 16:38 +0200 http://bitbucket.org/pypy/pypy/changeset/3bf64dd0bbef/ Log: Kill and simplify a lot of code diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -902,39 +902,6 @@ op.args[0]], resultvar=op.result) - def gct_gc_shadowstackref_new(self, hop): - op = hop.spaceop - livevars = self.push_roots(hop) - hop.genop("direct_call", [self.root_walker.gc_shadowstackref_new_ptr], - resultvar=op.result) - self.pop_roots(hop, livevars) - - def gct_gc_shadowstackref_context(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]], - resultvar=op.result) - - def gct_gc_save_current_state_away(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_save_current_state_away_ptr, - op.args[0], op.args[1]]) - - def gct_gc_forget_current_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_forget_current_state_ptr]) - - def gct_gc_restore_state_from(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_restore_state_from_ptr, - op.args[0]]) - - def gct_gc_start_fresh_new_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_start_fresh_new_state_ptr]) - def gct_do_malloc_fixedsize(self, hop): # used by the JIT (see rpython.jit.backend.llsupport.gc) op = hop.spaceop diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -219,52 +219,8 @@ minimal_transform=False) def need_stacklet_support(self, gctransformer, getfn): - shadow_stack_pool = self.shadow_stack_pool - SHADOWSTACKREF = get_shadowstackref(self, gctransformer) - - def gc_shadowstackref_new(): - ssref = shadow_stack_pool.allocate(SHADOWSTACKREF) - return lltype.cast_opaque_ptr(llmemory.GCREF, ssref) - - def gc_shadowstackref_context(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - return ssref.context - - def gc_save_current_state_away(gcref, ncontext): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.save_current_state_away(ssref, ncontext) - - def gc_forget_current_state(): - shadow_stack_pool.forget_current_state() - - def gc_restore_state_from(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.restore_state_from(ssref) - - def gc_start_fresh_new_state(): - shadow_stack_pool.start_fresh_new_state() - - s_gcref = SomePtr(llmemory.GCREF) - s_addr = SomeAddress() - self.gc_shadowstackref_new_ptr = getfn(gc_shadowstackref_new, - [], s_gcref, - minimal_transform=False) - self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context, - [s_gcref], s_addr, - inline=True) - self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away, - [s_gcref, s_addr], - annmodel.s_None, - inline=True) - self.gc_forget_current_state_ptr = getfn(gc_forget_current_state, - [], annmodel.s_None, - inline=True) - self.gc_restore_state_from_ptr = getfn(gc_restore_state_from, - [s_gcref], annmodel.s_None, - inline=True) - self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state, - [], annmodel.s_None, - inline=True) + from rpython.rlib import _stacklet_shadowstack + _stacklet_shadowstack.complete_destrptr(gctransformer) # ____________________________________________________________ diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -1,104 +1,176 @@ from rpython.rlib import _rffi_stacklet as _c from rpython.rlib.debug import ll_assert -from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rlib import rgc +from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.annotator import model as annmodel +from rpython.rtyper.llannotation import lltype_to_annotation -NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO) +# +# A GC wrapper around the C stacklet handles, with additionally a +# copy of the shadowstack (for all stacklets different than the main) +# +STACKLET = lltype.GcStruct('Stacklet', + ('s_handle', _c.handle), + ('s_sscopy', llmemory.Address), + rtti=True) +STACKLET_PTR = lltype.Ptr(STACKLET) +NULL_STACKLET = lltype.nullptr(STACKLET) +def complete_destrptr(gctransformer): + translator = gctransformer.translator + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + args_s = [lltype_to_annotation(STACKLET_PTR)] + s_result = annmodel.s_None + destrptr = mixlevelannotator.delayedfunction(stacklet_destructor, + args_s, s_result) + mixlevelannotator.finish() + lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr) + +def stacklet_destructor(stacklet): + sscopy = stacklet.s_sscopy + if sscopy: + llmemory.raw_free(sscopy) + h = stacklet.s_handle + if h: + _c.destroy(h) + + +SIZEADDR = llmemory.sizeof(llmemory.Address) + +def customtrace(gc, obj, callback, arg): + stacklet = llmemory.cast_adr_to_ptr(obj, STACKLET_PTR) + sscopy = stacklet.s_sscopy + if sscopy: + length_bytes = sscopy.signed[0] + while length_bytes > 0: + addr = sscopy + length_bytes + gc._trace_callback(callback, arg, addr) + length_bytes -= SIZEADDR +lambda_customtrace = lambda: customtrace + +def sscopy_detach_shadow_stack(): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + top = llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] + length_bytes = top - base + result = llmemory.raw_malloc(SIZEADDR + length_bytes) + if result: + result.signed[0] = length_bytes + llmemory.raw_memcopy(base, result + SIZEADDR, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = base + return result + +def sscopy_attach_shadow_stack(sscopy): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + ll_assert(llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]==base, + "attach_shadow_stack: ss is not empty?") + length_bytes = sscopy.signed[0] + llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = ( + base + length_bytes) + llmemory.raw_free(sscopy) + +def alloc_stacklet(): + new_stacklet = lltype.malloc(STACKLET) + new_stacklet.s_handle = _c.null_handle + return new_stacklet + +def attach_handle_on_stacklet(stacklet, h): + if not h: + raise MemoryError + elif _c.is_empty_handle(h): + ll_assert(gcrootfinder.sscopy == llmemory.NULL, + "empty_handle but sscopy != NULL") + return NULL_STACKLET + else: + # This is a return that gave us a real handle. Store it. + stacklet.s_handle = h + stacklet.s_sscopy = gcrootfinder.sscopy + ll_assert(gcrootfinder.sscopy != llmemory.NULL, + "!empty_handle but sscopy == NULL") + gcrootfinder.sscopy = llmemory.NULL + llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(stacklet)) + return stacklet + +def consume_stacklet(stacklet): + h = stacklet.s_handle + ll_assert(bool(h), "consume_stacklet: null handle") + stacklet.s_handle = _c.null_handle + stacklet.s_sscopy = llmemory.NULL + return h + def _new_callback(h, arg): - # We still have the old shadowstack active at this point; save it - # away, and start a fresh new one - oldsuspstack = gcrootfinder.oldsuspstack - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, - oldsuspstack, h) - llop.gc_start_fresh_new_state(lltype.Void) - gcrootfinder.oldsuspstack = NULL_SUSPSTACK + # There is a fresh stacklet object waiting on the gcrootfinder, + # so populate it with data that represents the parent suspended + # stacklet and detach the stacklet object from gcrootfinder. + stacklet = gcrootfinder.fresh_stacklet + gcrootfinder.fresh_stacklet = NULL_STACKLET + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #1") + stacklet = attach_handle_on_stacklet(stacklet, h) + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #2") # - newsuspstack = gcrootfinder.callback(oldsuspstack, arg) + # Call the main function provided by the (RPython) user. + stacklet = gcrootfinder.runfn(stacklet, arg) # - # Finishing this stacklet. - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = newsuspstack - h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack) - return llmemory.cast_adr_to_ptr(h, _c.handle) + # Here, 'stacklet' points to the target stacklet to which we want + # to jump to next. Read the 'handle' and forget about the + # stacklet object. + gcrootfinder.sscopy = llmemory.NULL + return consume_stacklet(stacklet) -def prepare_old_suspstack(): - if not gcrootfinder.oldsuspstack: # else reuse the one still there - _allocate_old_suspstack() +def _new(thread_handle, arg): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) + sscopy_attach_shadow_stack(sscopy) + return h +_new._dont_inline_ = True -def _allocate_old_suspstack(): - suspstack = llop.gc_shadowstackref_new(llmemory.GCREF) - gcrootfinder.oldsuspstack = suspstack -_allocate_old_suspstack._dont_inline_ = True - -def get_result_suspstack(h): - # Now we are in the target, after the switch() or the new(). - # Note that this whole module was carefully written in such a way as - # not to invoke pushing/popping things off the shadowstack at - # unexpected moments... - oldsuspstack = gcrootfinder.oldsuspstack - newsuspstack = gcrootfinder.newsuspstack - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = NULL_SUSPSTACK - if not h: - raise MemoryError - # We still have the old shadowstack active at this point; save it - # away, and restore the new one - if oldsuspstack: - ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle") - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, oldsuspstack, h) - else: - ll_assert(_c.is_empty_handle(h),"unexpected non-empty stacklet handle") - llop.gc_forget_current_state(lltype.Void) - # - llop.gc_restore_state_from(lltype.Void, newsuspstack) - # - # From this point on, 'newsuspstack' is consumed and done, its - # shadow stack installed as the current one. It should not be - # used any more. For performance, we avoid it being deallocated - # by letting it be reused on the next switch. - gcrootfinder.oldsuspstack = newsuspstack - # Return. - return oldsuspstack +def _switch(h): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.switch(h) + sscopy_attach_shadow_stack(sscopy) + return h +_switch._dont_inline_ = True class StackletGcRootFinder(object): - def new(thrd, callback, arg): - gcrootfinder.callback = callback - thread_handle = thrd._thrd - prepare_old_suspstack() - h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) - return get_result_suspstack(h) - new._dont_inline_ = True - new = staticmethod(new) - - def switch(suspstack): - # suspstack has a handle to target, i.e. where to switch to - ll_assert(suspstack != gcrootfinder.oldsuspstack, - "stacklet: invalid use") - gcrootfinder.newsuspstack = suspstack - h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) - h = llmemory.cast_adr_to_ptr(h, _c.handle) - prepare_old_suspstack() - h = _c.switch(h) - return get_result_suspstack(h) - switch._dont_inline_ = True - switch = staticmethod(switch) + fresh_stacklet = NULL_STACKLET @staticmethod - def is_empty_handle(suspstack): - return not suspstack + def new(thrd, callback, arg): + rgc.register_custom_trace_hook(STACKLET, lambda_customtrace) + result_stacklet = alloc_stacklet() + gcrootfinder.fresh_stacklet = alloc_stacklet() + gcrootfinder.runfn = callback + thread_handle = thrd._thrd + h = _new(thread_handle, arg) + return attach_handle_on_stacklet(result_stacklet, h) + + @staticmethod + def switch(stacklet): + # 'stacklet' has a handle to target, i.e. where to switch to + h = consume_stacklet(stacklet) + h = _switch(h) + return attach_handle_on_stacklet(stacklet, h) + + @staticmethod + def is_empty_handle(stacklet): + return not stacklet @staticmethod def get_null_handle(): - return NULL_SUSPSTACK + return NULL_STACKLET gcrootfinder = StackletGcRootFinder() -gcrootfinder.oldsuspstack = NULL_SUSPSTACK -gcrootfinder.newsuspstack = NULL_SUSPSTACK diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -890,19 +890,6 @@ def op_gc_reattach_callback_pieces(self): raise NotImplementedError("gc_reattach_callback_pieces") - def op_gc_shadowstackref_new(self): # stacklet+shadowstack - raise NotImplementedError("gc_shadowstackref_new") - def op_gc_shadowstackref_context(self): - raise NotImplementedError("gc_shadowstackref_context") - def op_gc_save_current_state_away(self): - raise NotImplementedError("gc_save_current_state_away") - def op_gc_forget_current_state(self): - raise NotImplementedError("gc_forget_current_state") - def op_gc_restore_state_from(self): - raise NotImplementedError("gc_restore_state_from") - def op_gc_start_fresh_new_state(self): - raise NotImplementedError("gc_start_fresh_new_state") - def op_gc_get_type_info_group(self): raise NotImplementedError("gc_get_type_info_group") 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 @@ -521,14 +521,6 @@ 'gc_detach_callback_pieces': LLOp(), 'gc_reattach_callback_pieces': LLOp(), - # for stacklet+shadowstack support - 'gc_shadowstackref_new': LLOp(canmallocgc=True), - 'gc_shadowstackref_context': LLOp(), - 'gc_save_current_state_away': LLOp(), - 'gc_forget_current_state': LLOp(), - 'gc_restore_state_from': LLOp(), - 'gc_start_fresh_new_state': LLOp(), - # NOTE NOTE NOTE! don't forget *** canmallocgc=True *** for anything that # can malloc a GC object. From noreply at buildbot.pypy.org Fri Sep 25 16:46:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 16:46:36 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move-2: Backout the issue #2017 fixes, now that they are not really needed Message-ID: <20150925144636.41AB81C065A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move-2 Changeset: r79827:c137e4ccaacd Date: 2015-09-25 16:46 +0200 http://bitbucket.org/pypy/pypy/changeset/c137e4ccaacd/ Log: Backout the issue #2017 fixes, now that they are not really needed any more. This should indirectly fix issue #2141. diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -180,7 +180,7 @@ thread_stacks[gcdata.active_tid] = old_ref # # no GC operation from here -- switching shadowstack! - shadow_stack_pool.save_current_state_away(old_ref, llmemory.NULL) + shadow_stack_pool.save_current_state_away(old_ref) if new_ref: shadow_stack_pool.restore_state_from(new_ref) else: @@ -225,18 +225,11 @@ # ____________________________________________________________ class ShadowStackPool(object): - """Manages a pool of shadowstacks. The MAX most recently used - shadowstacks are fully allocated and can be directly jumped into - (called "full stacks" below). - The rest are stored in a more virtual-memory-friendly way, i.e. - with just the right amount malloced. Before they can run, they - must be copied into a full shadowstack. + """Manages a pool of shadowstacks. """ _alloc_flavor_ = "raw" root_stack_depth = 163840 - MAX = 20 - def __init__(self, gcdata): self.unused_full_stack = llmemory.NULL self.gcdata = gcdata @@ -249,28 +242,18 @@ """Allocate an empty SHADOWSTACKREF object.""" return lltype.malloc(SHADOWSTACKREF, zero=True) - def save_current_state_away(self, shadowstackref, ncontext): + def save_current_state_away(self, shadowstackref): """Save the current state away into 'shadowstackref'. This either works, or raise MemoryError and nothing is done. To do a switch, first call save_current_state_away() or forget_current_state(), and then call restore_state_from() or start_fresh_new_state(). """ - fresh_free_fullstack = shadowstackref.prepare_free_slot() - if self.unused_full_stack: - if fresh_free_fullstack: - llmemory.raw_free(fresh_free_fullstack) - elif fresh_free_fullstack: - self.unused_full_stack = fresh_free_fullstack - else: - self._prepare_unused_stack() - # + self._prepare_unused_stack() shadowstackref.base = self.gcdata.root_stack_base shadowstackref.top = self.gcdata.root_stack_top - shadowstackref.context = ncontext ll_assert(shadowstackref.base <= shadowstackref.top, "save_current_state_away: broken shadowstack") - shadowstackref.attach() # # cannot use llop.gc_writebarrier() here, because # we are in a minimally-transformed GC helper :-/ @@ -293,7 +276,6 @@ ll_assert(bool(shadowstackref.base), "empty shadowstackref!") ll_assert(shadowstackref.base <= shadowstackref.top, "restore_state_from: broken shadowstack") - self.unused_full_stack = shadowstackref.rebuild(self.unused_full_stack) self.gcdata.root_stack_base = shadowstackref.base self.gcdata.root_stack_top = shadowstackref.top self._cleanup(shadowstackref) @@ -306,127 +288,28 @@ def _cleanup(self, shadowstackref): shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL - shadowstackref.context = llmemory.NULL def _prepare_unused_stack(self): - ll_assert(self.unused_full_stack == llmemory.NULL, - "already an unused_full_stack") - root_stack_size = sizeofaddr * self.root_stack_depth - self.unused_full_stack = llmemory.raw_malloc(root_stack_size) if self.unused_full_stack == llmemory.NULL: - raise MemoryError + root_stack_size = sizeofaddr * self.root_stack_depth + self.unused_full_stack = llmemory.raw_malloc(root_stack_size) + if self.unused_full_stack == llmemory.NULL: + raise MemoryError def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF - # Helpers to same virtual address space by limiting to MAX the - # number of full shadow stacks. If there are more, we compact - # them into a separately-allocated zone of memory of just the right - # size. See the comments in the definition of fullstack_cache below. - - def ll_prepare_free_slot(_unused): - """Free up a slot in the array of MAX entries, ready for storing - a new shadowstackref. Return the memory of the now-unused full - shadowstack. - """ - index = fullstack_cache[0] - if index > 0: - return llmemory.NULL # there is already at least one free slot - # - # make a compact copy in one old entry and return the - # original full-sized memory - index = -index - ll_assert(index > 0, "prepare_free_slot: cache[0] == 0") - compacting = lltype.cast_int_to_ptr(SHADOWSTACKREFPTR, - fullstack_cache[index]) - index += 1 - if index >= ShadowStackPool.MAX: - index = 1 - fullstack_cache[0] = -index # update to the next value in order - # - compacting.detach() - original = compacting.base - size = compacting.top - original - new = llmemory.raw_malloc(size) - if new == llmemory.NULL: - return llmemory.NULL - llmemory.raw_memcopy(original, new, size) - compacting.base = new - compacting.top = new + size - return original - - def ll_attach(shadowstackref): - """After prepare_free_slot(), store a shadowstackref in that slot.""" - index = fullstack_cache[0] - ll_assert(index > 0, "fullstack attach: no free slot") - fullstack_cache[0] = fullstack_cache[index] - fullstack_cache[index] = lltype.cast_ptr_to_int(shadowstackref) - ll_assert(shadowstackref.fsindex == 0, "fullstack attach: already one?") - shadowstackref.fsindex = index # > 0 - - def ll_detach(shadowstackref): - """Detach a shadowstackref from the array of MAX entries.""" - index = shadowstackref.fsindex - ll_assert(index > 0, "detach: unattached shadowstackref") - ll_assert(fullstack_cache[index] == - lltype.cast_ptr_to_int(shadowstackref), - "detach: bad fullstack_cache") - shadowstackref.fsindex = 0 - fullstack_cache[index] = fullstack_cache[0] - fullstack_cache[0] = index - - def ll_rebuild(shadowstackref, fullstack_base): - if shadowstackref.fsindex > 0: - shadowstackref.detach() - return fullstack_base - else: - # make an expanded copy of the compact shadowstack stored in - # 'shadowstackref' and free that - compact = shadowstackref.base - size = shadowstackref.top - compact - shadowstackref.base = fullstack_base - shadowstackref.top = fullstack_base + size - llmemory.raw_memcopy(compact, fullstack_base, size) - llmemory.raw_free(compact) - return llmemory.NULL - SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef', - ('base', llmemory.Address), - ('top', llmemory.Address), - ('context', llmemory.Address), - ('fsindex', lltype.Signed), - rtti=True, - adtmeths={'prepare_free_slot': ll_prepare_free_slot, - 'attach': ll_attach, - 'detach': ll_detach, - 'rebuild': ll_rebuild}) + ('base', llmemory.Address), + ('top', llmemory.Address), + rtti=True) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) - # Items 1..MAX-1 of the following array can be SHADOWSTACKREF - # addresses cast to integer. Or, they are small numbers and they - # make up a free list, rooted in item 0, which goes on until - # terminated with a negative item. This negative item gives (the - # opposite of) the index of the entry we try to remove next. - # Initially all items are in this free list and the end is '-1'. - fullstack_cache = lltype.malloc(lltype.Array(lltype.Signed), - ShadowStackPool.MAX, - flavor='raw', immortal=True) - for i in range(len(fullstack_cache) - 1): - fullstack_cache[i] = i + 1 - fullstack_cache[len(fullstack_cache) - 1] = -1 - def customtrace(gc, obj, callback, arg): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) - index = obj.fsindex - if index > 0: - # Haaaaaaack: fullstack_cache[] is just an integer, so it - # doesn't follow the SHADOWSTACKREF when it moves. But we - # know this customtrace() will be called just after the - # move. So we fix the fullstack_cache[] now... :-/ - fullstack_cache[index] = lltype.cast_ptr_to_int(obj) addr = obj.top start = obj.base while addr != start: @@ -440,22 +323,10 @@ (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): - if root_walker.stacklet_support: - from rpython.rlib import _rffi_stacklet as _c - h = shadowstackref.context - h = llmemory.cast_adr_to_ptr(h, _c.handle) - shadowstackref.context = llmemory.NULL - # - if shadowstackref.fsindex > 0: - shadowstackref.detach() base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) - # - if root_walker.stacklet_support: - if h: - _c.destroy(h) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) From noreply at buildbot.pypy.org Fri Sep 25 18:02:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:46 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head a5036b5b1dd8 on branch reflex-support Message-ID: <20150925160246.7C1BF1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79828:d492b35efbb8 Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/d492b35efbb8/ Log: Merge closed head a5036b5b1dd8 on branch reflex-support From noreply at buildbot.pypy.org Fri Sep 25 18:02:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:48 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head ee4fde461c8b on branch vecopt-merge-iterator-sharing Message-ID: <20150925160248.7BDA91C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79829:7fc21e3d6a39 Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/7fc21e3d6a39/ Log: Merge closed head ee4fde461c8b on branch vecopt-merge-iterator- sharing From noreply at buildbot.pypy.org Fri Sep 25 18:02:50 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:50 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head e9e3e4efdb25 on branch vecopt2 Message-ID: <20150925160250.706491C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79830:5f345c535abb Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/5f345c535abb/ Log: Merge closed head e9e3e4efdb25 on branch vecopt2 From noreply at buildbot.pypy.org Fri Sep 25 18:02:52 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:52 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head b414e83c5a5f on branch vecopt-merge-opt Message-ID: <20150925160252.531AF1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79831:64c3f3b34e14 Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/64c3f3b34e14/ Log: Merge closed head b414e83c5a5f on branch vecopt-merge-opt From noreply at buildbot.pypy.org Fri Sep 25 18:02:54 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:54 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 078a0334c34d on branch memoryerror Message-ID: <20150925160254.4AE3B1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79832:bf8b1ffb282b Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/bf8b1ffb282b/ Log: Merge closed head 078a0334c34d on branch memoryerror From noreply at buildbot.pypy.org Fri Sep 25 18:02:56 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:56 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 10cb9ba203a9 on branch memoryerror2 Message-ID: <20150925160256.45CC41C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79833:c558e06fbf23 Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/c558e06fbf23/ Log: Merge closed head 10cb9ba203a9 on branch memoryerror2 From noreply at buildbot.pypy.org Fri Sep 25 18:02:58 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:02:58 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head f693472e325f on branch memoryerror3 Message-ID: <20150925160258.263901C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79834:07798733cb5d Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/07798733cb5d/ Log: Merge closed head f693472e325f on branch memoryerror3 From noreply at buildbot.pypy.org Fri Sep 25 18:03:00 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:03:00 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 94bb91d002b0 on branch optresult Message-ID: <20150925160300.1A50F1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79835:6689660c1fc5 Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/6689660c1fc5/ Log: Merge closed head 94bb91d002b0 on branch optresult From noreply at buildbot.pypy.org Fri Sep 25 18:03:02 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:03:02 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: Merge closed head 39acaa1aae45 on branch shadowstack-no-move Message-ID: <20150925160302.17A6A1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79836:0fdbbc77e30d Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/0fdbbc77e30d/ Log: Merge closed head 39acaa1aae45 on branch shadowstack-no-move From noreply at buildbot.pypy.org Fri Sep 25 18:03:03 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:03:03 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: re-close this branch Message-ID: <20150925160303.F007D1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: closed-branches Changeset: r79837:6ceaec9249ee Date: 2015-09-25 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/6ceaec9249ee/ Log: re-close this branch From noreply at buildbot.pypy.org Fri Sep 25 18:03:05 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:03:05 +0200 (CEST) Subject: [pypy-commit] pypy shadowstack-no-move-2: Close branch ready for merge Message-ID: <20150925160305.F00111C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: shadowstack-no-move-2 Changeset: r79838:e474cd061c80 Date: 2015-09-25 17:39 +0200 http://bitbucket.org/pypy/pypy/changeset/e474cd061c80/ Log: Close branch ready for merge From noreply at buildbot.pypy.org Fri Sep 25 18:03:08 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:03:08 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge shadowstack-no-move-2 Message-ID: <20150925160308.575DD1C1E6D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79839:32ee5bd50cd0 Date: 2015-09-25 17:40 +0200 http://bitbucket.org/pypy/pypy/changeset/32ee5bd50cd0/ Log: hg merge shadowstack-no-move-2 Fix issues #2141 and #2017. Removes the previous fix for issue #2017. diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -902,39 +902,6 @@ op.args[0]], resultvar=op.result) - def gct_gc_shadowstackref_new(self, hop): - op = hop.spaceop - livevars = self.push_roots(hop) - hop.genop("direct_call", [self.root_walker.gc_shadowstackref_new_ptr], - resultvar=op.result) - self.pop_roots(hop, livevars) - - def gct_gc_shadowstackref_context(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]], - resultvar=op.result) - - def gct_gc_save_current_state_away(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_save_current_state_away_ptr, - op.args[0], op.args[1]]) - - def gct_gc_forget_current_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_forget_current_state_ptr]) - - def gct_gc_restore_state_from(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_restore_state_from_ptr, - op.args[0]]) - - def gct_gc_start_fresh_new_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_start_fresh_new_state_ptr]) - def gct_do_malloc_fixedsize(self, hop): # used by the JIT (see rpython.jit.backend.llsupport.gc) op = hop.spaceop diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -180,7 +180,7 @@ thread_stacks[gcdata.active_tid] = old_ref # # no GC operation from here -- switching shadowstack! - shadow_stack_pool.save_current_state_away(old_ref, llmemory.NULL) + shadow_stack_pool.save_current_state_away(old_ref) if new_ref: shadow_stack_pool.restore_state_from(new_ref) else: @@ -219,68 +219,17 @@ minimal_transform=False) def need_stacklet_support(self, gctransformer, getfn): - shadow_stack_pool = self.shadow_stack_pool - SHADOWSTACKREF = get_shadowstackref(self, gctransformer) - - def gc_shadowstackref_new(): - ssref = shadow_stack_pool.allocate(SHADOWSTACKREF) - return lltype.cast_opaque_ptr(llmemory.GCREF, ssref) - - def gc_shadowstackref_context(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - return ssref.context - - def gc_save_current_state_away(gcref, ncontext): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.save_current_state_away(ssref, ncontext) - - def gc_forget_current_state(): - shadow_stack_pool.forget_current_state() - - def gc_restore_state_from(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.restore_state_from(ssref) - - def gc_start_fresh_new_state(): - shadow_stack_pool.start_fresh_new_state() - - s_gcref = SomePtr(llmemory.GCREF) - s_addr = SomeAddress() - self.gc_shadowstackref_new_ptr = getfn(gc_shadowstackref_new, - [], s_gcref, - minimal_transform=False) - self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context, - [s_gcref], s_addr, - inline=True) - self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away, - [s_gcref, s_addr], - annmodel.s_None, - inline=True) - self.gc_forget_current_state_ptr = getfn(gc_forget_current_state, - [], annmodel.s_None, - inline=True) - self.gc_restore_state_from_ptr = getfn(gc_restore_state_from, - [s_gcref], annmodel.s_None, - inline=True) - self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state, - [], annmodel.s_None, - inline=True) + from rpython.rlib import _stacklet_shadowstack + _stacklet_shadowstack.complete_destrptr(gctransformer) # ____________________________________________________________ class ShadowStackPool(object): - """Manages a pool of shadowstacks. The MAX most recently used - shadowstacks are fully allocated and can be directly jumped into - (called "full stacks" below). - The rest are stored in a more virtual-memory-friendly way, i.e. - with just the right amount malloced. Before they can run, they - must be copied into a full shadowstack. + """Manages a pool of shadowstacks. """ _alloc_flavor_ = "raw" root_stack_depth = 163840 - MAX = 20 - def __init__(self, gcdata): self.unused_full_stack = llmemory.NULL self.gcdata = gcdata @@ -293,28 +242,18 @@ """Allocate an empty SHADOWSTACKREF object.""" return lltype.malloc(SHADOWSTACKREF, zero=True) - def save_current_state_away(self, shadowstackref, ncontext): + def save_current_state_away(self, shadowstackref): """Save the current state away into 'shadowstackref'. This either works, or raise MemoryError and nothing is done. To do a switch, first call save_current_state_away() or forget_current_state(), and then call restore_state_from() or start_fresh_new_state(). """ - fresh_free_fullstack = shadowstackref.prepare_free_slot() - if self.unused_full_stack: - if fresh_free_fullstack: - llmemory.raw_free(fresh_free_fullstack) - elif fresh_free_fullstack: - self.unused_full_stack = fresh_free_fullstack - else: - self._prepare_unused_stack() - # + self._prepare_unused_stack() shadowstackref.base = self.gcdata.root_stack_base shadowstackref.top = self.gcdata.root_stack_top - shadowstackref.context = ncontext ll_assert(shadowstackref.base <= shadowstackref.top, "save_current_state_away: broken shadowstack") - shadowstackref.attach() # # cannot use llop.gc_writebarrier() here, because # we are in a minimally-transformed GC helper :-/ @@ -337,7 +276,6 @@ ll_assert(bool(shadowstackref.base), "empty shadowstackref!") ll_assert(shadowstackref.base <= shadowstackref.top, "restore_state_from: broken shadowstack") - self.unused_full_stack = shadowstackref.rebuild(self.unused_full_stack) self.gcdata.root_stack_base = shadowstackref.base self.gcdata.root_stack_top = shadowstackref.top self._cleanup(shadowstackref) @@ -350,127 +288,28 @@ def _cleanup(self, shadowstackref): shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL - shadowstackref.context = llmemory.NULL def _prepare_unused_stack(self): - ll_assert(self.unused_full_stack == llmemory.NULL, - "already an unused_full_stack") - root_stack_size = sizeofaddr * self.root_stack_depth - self.unused_full_stack = llmemory.raw_malloc(root_stack_size) if self.unused_full_stack == llmemory.NULL: - raise MemoryError + root_stack_size = sizeofaddr * self.root_stack_depth + self.unused_full_stack = llmemory.raw_malloc(root_stack_size) + if self.unused_full_stack == llmemory.NULL: + raise MemoryError def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF - # Helpers to same virtual address space by limiting to MAX the - # number of full shadow stacks. If there are more, we compact - # them into a separately-allocated zone of memory of just the right - # size. See the comments in the definition of fullstack_cache below. - - def ll_prepare_free_slot(_unused): - """Free up a slot in the array of MAX entries, ready for storing - a new shadowstackref. Return the memory of the now-unused full - shadowstack. - """ - index = fullstack_cache[0] - if index > 0: - return llmemory.NULL # there is already at least one free slot - # - # make a compact copy in one old entry and return the - # original full-sized memory - index = -index - ll_assert(index > 0, "prepare_free_slot: cache[0] == 0") - compacting = lltype.cast_int_to_ptr(SHADOWSTACKREFPTR, - fullstack_cache[index]) - index += 1 - if index >= ShadowStackPool.MAX: - index = 1 - fullstack_cache[0] = -index # update to the next value in order - # - compacting.detach() - original = compacting.base - size = compacting.top - original - new = llmemory.raw_malloc(size) - if new == llmemory.NULL: - return llmemory.NULL - llmemory.raw_memcopy(original, new, size) - compacting.base = new - compacting.top = new + size - return original - - def ll_attach(shadowstackref): - """After prepare_free_slot(), store a shadowstackref in that slot.""" - index = fullstack_cache[0] - ll_assert(index > 0, "fullstack attach: no free slot") - fullstack_cache[0] = fullstack_cache[index] - fullstack_cache[index] = lltype.cast_ptr_to_int(shadowstackref) - ll_assert(shadowstackref.fsindex == 0, "fullstack attach: already one?") - shadowstackref.fsindex = index # > 0 - - def ll_detach(shadowstackref): - """Detach a shadowstackref from the array of MAX entries.""" - index = shadowstackref.fsindex - ll_assert(index > 0, "detach: unattached shadowstackref") - ll_assert(fullstack_cache[index] == - lltype.cast_ptr_to_int(shadowstackref), - "detach: bad fullstack_cache") - shadowstackref.fsindex = 0 - fullstack_cache[index] = fullstack_cache[0] - fullstack_cache[0] = index - - def ll_rebuild(shadowstackref, fullstack_base): - if shadowstackref.fsindex > 0: - shadowstackref.detach() - return fullstack_base - else: - # make an expanded copy of the compact shadowstack stored in - # 'shadowstackref' and free that - compact = shadowstackref.base - size = shadowstackref.top - compact - shadowstackref.base = fullstack_base - shadowstackref.top = fullstack_base + size - llmemory.raw_memcopy(compact, fullstack_base, size) - llmemory.raw_free(compact) - return llmemory.NULL - SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef', - ('base', llmemory.Address), - ('top', llmemory.Address), - ('context', llmemory.Address), - ('fsindex', lltype.Signed), - rtti=True, - adtmeths={'prepare_free_slot': ll_prepare_free_slot, - 'attach': ll_attach, - 'detach': ll_detach, - 'rebuild': ll_rebuild}) + ('base', llmemory.Address), + ('top', llmemory.Address), + rtti=True) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) - # Items 1..MAX-1 of the following array can be SHADOWSTACKREF - # addresses cast to integer. Or, they are small numbers and they - # make up a free list, rooted in item 0, which goes on until - # terminated with a negative item. This negative item gives (the - # opposite of) the index of the entry we try to remove next. - # Initially all items are in this free list and the end is '-1'. - fullstack_cache = lltype.malloc(lltype.Array(lltype.Signed), - ShadowStackPool.MAX, - flavor='raw', immortal=True) - for i in range(len(fullstack_cache) - 1): - fullstack_cache[i] = i + 1 - fullstack_cache[len(fullstack_cache) - 1] = -1 - def customtrace(gc, obj, callback, arg): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) - index = obj.fsindex - if index > 0: - # Haaaaaaack: fullstack_cache[] is just an integer, so it - # doesn't follow the SHADOWSTACKREF when it moves. But we - # know this customtrace() will be called just after the - # move. So we fix the fullstack_cache[] now... :-/ - fullstack_cache[index] = lltype.cast_ptr_to_int(obj) addr = obj.top start = obj.base while addr != start: @@ -484,22 +323,10 @@ (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): - if root_walker.stacklet_support: - from rpython.rlib import _rffi_stacklet as _c - h = shadowstackref.context - h = llmemory.cast_adr_to_ptr(h, _c.handle) - shadowstackref.context = llmemory.NULL - # - if shadowstackref.fsindex > 0: - shadowstackref.detach() base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) - # - if root_walker.stacklet_support: - if h: - _c.destroy(h) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -1,104 +1,176 @@ from rpython.rlib import _rffi_stacklet as _c from rpython.rlib.debug import ll_assert -from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rlib import rgc +from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.annotator import model as annmodel +from rpython.rtyper.llannotation import lltype_to_annotation -NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO) +# +# A GC wrapper around the C stacklet handles, with additionally a +# copy of the shadowstack (for all stacklets different than the main) +# +STACKLET = lltype.GcStruct('Stacklet', + ('s_handle', _c.handle), + ('s_sscopy', llmemory.Address), + rtti=True) +STACKLET_PTR = lltype.Ptr(STACKLET) +NULL_STACKLET = lltype.nullptr(STACKLET) +def complete_destrptr(gctransformer): + translator = gctransformer.translator + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + args_s = [lltype_to_annotation(STACKLET_PTR)] + s_result = annmodel.s_None + destrptr = mixlevelannotator.delayedfunction(stacklet_destructor, + args_s, s_result) + mixlevelannotator.finish() + lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr) + +def stacklet_destructor(stacklet): + sscopy = stacklet.s_sscopy + if sscopy: + llmemory.raw_free(sscopy) + h = stacklet.s_handle + if h: + _c.destroy(h) + + +SIZEADDR = llmemory.sizeof(llmemory.Address) + +def customtrace(gc, obj, callback, arg): + stacklet = llmemory.cast_adr_to_ptr(obj, STACKLET_PTR) + sscopy = stacklet.s_sscopy + if sscopy: + length_bytes = sscopy.signed[0] + while length_bytes > 0: + addr = sscopy + length_bytes + gc._trace_callback(callback, arg, addr) + length_bytes -= SIZEADDR +lambda_customtrace = lambda: customtrace + +def sscopy_detach_shadow_stack(): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + top = llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] + length_bytes = top - base + result = llmemory.raw_malloc(SIZEADDR + length_bytes) + if result: + result.signed[0] = length_bytes + llmemory.raw_memcopy(base, result + SIZEADDR, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = base + return result + +def sscopy_attach_shadow_stack(sscopy): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + ll_assert(llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]==base, + "attach_shadow_stack: ss is not empty?") + length_bytes = sscopy.signed[0] + llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = ( + base + length_bytes) + llmemory.raw_free(sscopy) + +def alloc_stacklet(): + new_stacklet = lltype.malloc(STACKLET) + new_stacklet.s_handle = _c.null_handle + return new_stacklet + +def attach_handle_on_stacklet(stacklet, h): + if not h: + raise MemoryError + elif _c.is_empty_handle(h): + ll_assert(gcrootfinder.sscopy == llmemory.NULL, + "empty_handle but sscopy != NULL") + return NULL_STACKLET + else: + # This is a return that gave us a real handle. Store it. + stacklet.s_handle = h + stacklet.s_sscopy = gcrootfinder.sscopy + ll_assert(gcrootfinder.sscopy != llmemory.NULL, + "!empty_handle but sscopy == NULL") + gcrootfinder.sscopy = llmemory.NULL + llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(stacklet)) + return stacklet + +def consume_stacklet(stacklet): + h = stacklet.s_handle + ll_assert(bool(h), "consume_stacklet: null handle") + stacklet.s_handle = _c.null_handle + stacklet.s_sscopy = llmemory.NULL + return h + def _new_callback(h, arg): - # We still have the old shadowstack active at this point; save it - # away, and start a fresh new one - oldsuspstack = gcrootfinder.oldsuspstack - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, - oldsuspstack, h) - llop.gc_start_fresh_new_state(lltype.Void) - gcrootfinder.oldsuspstack = NULL_SUSPSTACK + # There is a fresh stacklet object waiting on the gcrootfinder, + # so populate it with data that represents the parent suspended + # stacklet and detach the stacklet object from gcrootfinder. + stacklet = gcrootfinder.fresh_stacklet + gcrootfinder.fresh_stacklet = NULL_STACKLET + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #1") + stacklet = attach_handle_on_stacklet(stacklet, h) + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #2") # - newsuspstack = gcrootfinder.callback(oldsuspstack, arg) + # Call the main function provided by the (RPython) user. + stacklet = gcrootfinder.runfn(stacklet, arg) # - # Finishing this stacklet. - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = newsuspstack - h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack) - return llmemory.cast_adr_to_ptr(h, _c.handle) + # Here, 'stacklet' points to the target stacklet to which we want + # to jump to next. Read the 'handle' and forget about the + # stacklet object. + gcrootfinder.sscopy = llmemory.NULL + return consume_stacklet(stacklet) -def prepare_old_suspstack(): - if not gcrootfinder.oldsuspstack: # else reuse the one still there - _allocate_old_suspstack() +def _new(thread_handle, arg): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) + sscopy_attach_shadow_stack(sscopy) + return h +_new._dont_inline_ = True -def _allocate_old_suspstack(): - suspstack = llop.gc_shadowstackref_new(llmemory.GCREF) - gcrootfinder.oldsuspstack = suspstack -_allocate_old_suspstack._dont_inline_ = True - -def get_result_suspstack(h): - # Now we are in the target, after the switch() or the new(). - # Note that this whole module was carefully written in such a way as - # not to invoke pushing/popping things off the shadowstack at - # unexpected moments... - oldsuspstack = gcrootfinder.oldsuspstack - newsuspstack = gcrootfinder.newsuspstack - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = NULL_SUSPSTACK - if not h: - raise MemoryError - # We still have the old shadowstack active at this point; save it - # away, and restore the new one - if oldsuspstack: - ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle") - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, oldsuspstack, h) - else: - ll_assert(_c.is_empty_handle(h),"unexpected non-empty stacklet handle") - llop.gc_forget_current_state(lltype.Void) - # - llop.gc_restore_state_from(lltype.Void, newsuspstack) - # - # From this point on, 'newsuspstack' is consumed and done, its - # shadow stack installed as the current one. It should not be - # used any more. For performance, we avoid it being deallocated - # by letting it be reused on the next switch. - gcrootfinder.oldsuspstack = newsuspstack - # Return. - return oldsuspstack +def _switch(h): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.switch(h) + sscopy_attach_shadow_stack(sscopy) + return h +_switch._dont_inline_ = True class StackletGcRootFinder(object): - def new(thrd, callback, arg): - gcrootfinder.callback = callback - thread_handle = thrd._thrd - prepare_old_suspstack() - h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) - return get_result_suspstack(h) - new._dont_inline_ = True - new = staticmethod(new) - - def switch(suspstack): - # suspstack has a handle to target, i.e. where to switch to - ll_assert(suspstack != gcrootfinder.oldsuspstack, - "stacklet: invalid use") - gcrootfinder.newsuspstack = suspstack - h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) - h = llmemory.cast_adr_to_ptr(h, _c.handle) - prepare_old_suspstack() - h = _c.switch(h) - return get_result_suspstack(h) - switch._dont_inline_ = True - switch = staticmethod(switch) + fresh_stacklet = NULL_STACKLET @staticmethod - def is_empty_handle(suspstack): - return not suspstack + def new(thrd, callback, arg): + rgc.register_custom_trace_hook(STACKLET, lambda_customtrace) + result_stacklet = alloc_stacklet() + gcrootfinder.fresh_stacklet = alloc_stacklet() + gcrootfinder.runfn = callback + thread_handle = thrd._thrd + h = _new(thread_handle, arg) + return attach_handle_on_stacklet(result_stacklet, h) + + @staticmethod + def switch(stacklet): + # 'stacklet' has a handle to target, i.e. where to switch to + h = consume_stacklet(stacklet) + h = _switch(h) + return attach_handle_on_stacklet(stacklet, h) + + @staticmethod + def is_empty_handle(stacklet): + return not stacklet @staticmethod def get_null_handle(): - return NULL_SUSPSTACK + return NULL_STACKLET gcrootfinder = StackletGcRootFinder() -gcrootfinder.oldsuspstack = NULL_SUSPSTACK -gcrootfinder.newsuspstack = NULL_SUSPSTACK diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -890,19 +890,6 @@ def op_gc_reattach_callback_pieces(self): raise NotImplementedError("gc_reattach_callback_pieces") - def op_gc_shadowstackref_new(self): # stacklet+shadowstack - raise NotImplementedError("gc_shadowstackref_new") - def op_gc_shadowstackref_context(self): - raise NotImplementedError("gc_shadowstackref_context") - def op_gc_save_current_state_away(self): - raise NotImplementedError("gc_save_current_state_away") - def op_gc_forget_current_state(self): - raise NotImplementedError("gc_forget_current_state") - def op_gc_restore_state_from(self): - raise NotImplementedError("gc_restore_state_from") - def op_gc_start_fresh_new_state(self): - raise NotImplementedError("gc_start_fresh_new_state") - def op_gc_get_type_info_group(self): raise NotImplementedError("gc_get_type_info_group") 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 @@ -521,14 +521,6 @@ 'gc_detach_callback_pieces': LLOp(), 'gc_reattach_callback_pieces': LLOp(), - # for stacklet+shadowstack support - 'gc_shadowstackref_new': LLOp(canmallocgc=True), - 'gc_shadowstackref_context': LLOp(), - 'gc_save_current_state_away': LLOp(), - 'gc_forget_current_state': LLOp(), - 'gc_restore_state_from': LLOp(), - 'gc_start_fresh_new_state': LLOp(), - # NOTE NOTE NOTE! don't forget *** canmallocgc=True *** for anything that # can malloc a GC object. From noreply at buildbot.pypy.org Fri Sep 25 18:12:30 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:12:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Document shadowstack-no-move-2 Message-ID: <20150925161230.D60EC1C14AF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79840:44f3dafb7353 Date: 2015-09-25 18:12 +0200 http://bitbucket.org/pypy/pypy/changeset/44f3dafb7353/ Log: Document shadowstack-no-move-2 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 @@ -33,3 +33,9 @@ .. branch: remember-tracing-counts Reenable jithooks + +.. branch: detect_egd2 + +.. branch: shadowstack-no-move-2 +Issue #2141: fix a crash on Windows and OS/X and ARM when running +at least 20 threads. From noreply at buildbot.pypy.org Fri Sep 25 18:45:08 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 18:45:08 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix test__vmprof Message-ID: <20150925164508.8A3291C14AF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79841:9c3d2bdbb1fa Date: 2015-09-25 18:41 +0200 http://bitbucket.org/pypy/pypy/changeset/9c3d2bdbb1fa/ Log: Fix test__vmprof diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -34,6 +34,7 @@ i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) i += 2 * WORD + size * struct.calcsize("P") + i += WORD # thread id elif s[i] == '\x02': i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) From noreply at buildbot.pypy.org Fri Sep 25 19:43:48 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 25 Sep 2015 19:43:48 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ctypes: Implement array.ctypes Message-ID: <20150925174348.926171C135E@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: numpy-ctypes Changeset: r79842:3c27bfa5ee10 Date: 2015-09-25 18:43 +0100 http://bitbucket.org/pypy/pypy/changeset/3c27bfa5ee10/ Log: Implement array.ctypes diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -747,8 +747,12 @@ return out def descr_get_ctypes(self, space): - raise OperationError(space.w_NotImplementedError, space.wrap( - "ctypes not implemented yet")) + w_result = space.appexec([self], """(w_array): + from numpy.core import _internal + p_data = self.__array_interface__['data'][0] + return _internal.ctypes(self, p_data) + """) + return w_result def buffer_w(self, space, flags): return self.implementation.get_buffer(space, True) From noreply at buildbot.pypy.org Fri Sep 25 20:48:49 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 20:48:49 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: some translation issues indicated by test_zjit Message-ID: <20150925184849.E6DBA1C135E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79843:658ed0c0b405 Date: 2015-09-25 20:49 +0200 http://bitbucket.org/pypy/pypy/changeset/658ed0c0b405/ Log: some translation issues indicated by test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -18,6 +18,7 @@ return pyjitpl._warmrunnerdesc.metainterp_sd.profiler class TestNumpyJit(Jit386Mixin): + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll" graph = None interp = None @@ -97,6 +98,11 @@ backendopt=True, graph_and_interp_only=True, ProfilerClass=Profiler, + translate_support_code=True, + translationoptions={'gc':'minimark', + 'gcrootfinder': 'asmgcc', + 'gcremovetypeptr': False + }, vec=True) self.__class__.interp = interp self.__class__.graph = graph diff --git a/rpython/jit/backend/x86/vector_ext.py b/rpython/jit/backend/x86/vector_ext.py --- a/rpython/jit/backend/x86/vector_ext.py +++ b/rpython/jit/backend/x86/vector_ext.py @@ -99,7 +99,7 @@ else: not_implemented("accum operator %s not implemented" % (accum_info.accum_operation)) - accum_info = accum_info.prev + accum_info = accum_info.next() def _accum_reduce_mul(self, arg, accumloc, targetloc): scratchloc = X86_64_XMM_SCRATCH_REG diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -52,6 +52,9 @@ token.original_jitcell_token = jitcell_token jitcell_token.target_tokens.append(token) self.label.setdescr(token) + else: + token = self.jump.getdescr() + assert isinstance(token, TargetToken) if self.prefix_label: token = TargetToken(jitcell_token) token.original_jitcell_token = jitcell_token @@ -102,7 +105,7 @@ user_code = not jitdriver_sd.vec and warmstate.vec_all loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) if user_code and user_loop_bail_fast_path(loop, warmstate): - return + return loop_info, loop_ops # the original loop (output of optimize_unroll) info = LoopVersionInfo(loop_info) version = info.snapshot(loop) @@ -113,7 +116,7 @@ # start = time.clock() opt = VectorizingOptimizer(metainterp_sd, jitdriver_sd, warmstate.vec_cost) - index_vars = opt.propagate_all_forward(info, loop) + index_vars = opt.run_optimization(info, loop) gso = GuardStrengthenOpt(index_vars) gso.propagate_all_forward(info, loop, user_code) end = time.clock() @@ -144,6 +147,7 @@ llop.debug_print_traceback(lltype.Void) else: raise + return loop_info, loop_ops def user_loop_bail_fast_path(loop, warmstate): """ In a fast path over the trace loop: try to prevent vecopt @@ -200,7 +204,7 @@ self.smallest_type_bytes = 0 self.orig_label_args = None - def propagate_all_forward(self, info, loop): + def run_optimization(self, info, loop): self.orig_label_args = loop.label.getarglist_copy() self.linear_find_smallest_type(loop) byte_count = self.smallest_type_bytes diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -198,6 +198,12 @@ def get_forwarded(self): return self._forwarded +def vector_repr(self, num): + if self.opnum in (rop.VEC_UNPACK_I, rop.VEC_UNPACK_F): + return self.type + str(num) + return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, + self.bytesize * 8) + class AbstractResOp(AbstractResOpOrInputArg): """The central ResOperation class, representing one operation.""" @@ -308,8 +314,7 @@ num = len(memo) memo[self] = num if self.is_vector(): - assert isinstance(self, VectorOp) - sres = self.vector_repr(num) + ' = ' + sres = vector_repr(self, num) + ' = ' else: sres = self.type + str(num) + ' = ' #if self.result is not None: @@ -339,8 +344,7 @@ num = len(memo) memo[self] = num if self.is_vector(): - assert isinstance(self, VectorOp) - return self.vector_repr(num) + return vector_repr(self, num) return self.type + str(num) def __repr__(self): @@ -714,12 +718,6 @@ class VectorOp(object): _mixin_ = True - def vector_repr(self, num): - if self.opnum in (rop.VEC_UNPACK_I, rop.VEC_UNPACK_F): - return self.type + str(num) - return 'v%d[%dx%s%d]' % (num, self.count, self.datatype, - self.bytesize * 8) - def vector_bytesize(self): assert self.count > 0 return self.byte_size * self.count From noreply at buildbot.pypy.org Fri Sep 25 20:58:39 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 20:58:39 +0200 (CEST) Subject: [pypy-commit] cffi default: Py3 fix Message-ID: <20150925185839.E2F581C14AF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2273:7a485110c403 Date: 2015-09-25 20:59 +0200 http://bitbucket.org/cffi/cffi/changeset/7a485110c403/ Log: Py3 fix diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -880,7 +880,7 @@ # not partial (we can't complete or verify them!) and emit them # anonymously. lst = self._struct_unions.items() - lst.sort(key=lambda (tp, order): order) + lst.sort(key=lambda tp_order: tp_order[1]) for tp, order in lst: if tp not in self._seen_struct_unions: if tp.partial: From noreply at buildbot.pypy.org Fri Sep 25 20:59:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 25 Sep 2015 20:59:23 +0200 (CEST) Subject: [pypy-commit] cffi default: Probably need to save/restore the current exception here Message-ID: <20150925185923.54EA11C14AF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2274:2106b4532288 Date: 2015-09-25 21:00 +0200 http://bitbucket.org/cffi/cffi/changeset/2106b4532288/ Log: Probably need to save/restore the current exception here diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1661,6 +1661,11 @@ cdata_dealloc((CDataObject *)cd); if (destructor != NULL) { + PyObject *error_type, *error_value, *error_traceback; + + /* Save the current exception */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + result = PyObject_CallFunctionObjArgs(destructor, origobj, NULL); if (result != NULL) { Py_DECREF(result); @@ -1670,6 +1675,9 @@ origobj, NULL); } Py_DECREF(destructor); + + /* Restore the saved exception */ + PyErr_Restore(error_type, error_value, error_traceback); } Py_DECREF(origobj); } From noreply at buildbot.pypy.org Fri Sep 25 21:09:46 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Fri, 25 Sep 2015 21:09:46 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: parameter missing here, return value there, ... translation issues :) Message-ID: <20150925190946.E931D1C065A@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79844:2002cf4fb7d3 Date: 2015-09-25 21:09 +0200 http://bitbucket.org/pypy/pypy/changeset/2002cf4fb7d3/ Log: parameter missing here, return value there, ... translation issues :) diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -999,7 +999,6 @@ # saves the next modification that uses a variable self.next_nonconst = None self.current_end = None - self.opnum = 0 def stride_const(self): return self.next_nonconst is None diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -269,11 +269,11 @@ state.setvector_of_box(op,i,vecop) if pack.is_accumulating(): state.renamer.start_renaming(op, vecop) - if op.is_guard(): - assert isinstance(op, GuardResOp) + if left.is_guard(): + assert isinstance(left, GuardResOp) assert isinstance(vecop, GuardResOp) - vecop.setfailargs(op.getfailargs()) - vecop.rd_snapshot = op.rd_snapshot + vecop.setfailargs(left.getfailargs()) + vecop.rd_snapshot = left.rd_snapshot def prepare_arguments(state, pack, args): # Transforming one argument to a vector box argument @@ -885,6 +885,6 @@ def is_accumulating(self): return True - def clone(self): - return AccumPack(operations, self.operator, self.position) + def clone(self, oplist): + return AccumPack(oplist, self.operator, self.position) From noreply at buildbot.pypy.org Sat Sep 26 00:38:06 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 26 Sep 2015 00:38:06 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ctypes: fix typo Message-ID: <20150925223806.3E9A01C1EA1@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: numpy-ctypes Changeset: r79845:6a065e2c6443 Date: 2015-09-25 23:38 +0100 http://bitbucket.org/pypy/pypy/changeset/6a065e2c6443/ Log: fix typo diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -747,10 +747,10 @@ return out def descr_get_ctypes(self, space): - w_result = space.appexec([self], """(w_array): + w_result = space.appexec([self], """(arr): from numpy.core import _internal - p_data = self.__array_interface__['data'][0] - return _internal.ctypes(self, p_data) + p_data = arr.__array_interface__['data'][0] + return _internal.ctypes(arr, p_data) """) return w_result From noreply at buildbot.pypy.org Sat Sep 26 04:59:57 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 26 Sep 2015 04:59:57 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ctypes: fix another typo Message-ID: <20150926025957.F34AC1C14AF@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: numpy-ctypes Changeset: r79846:11de22433404 Date: 2015-09-26 04:00 +0100 http://bitbucket.org/pypy/pypy/changeset/11de22433404/ Log: fix another typo diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -750,7 +750,7 @@ w_result = space.appexec([self], """(arr): from numpy.core import _internal p_data = arr.__array_interface__['data'][0] - return _internal.ctypes(arr, p_data) + return _internal._ctypes(arr, p_data) """) return w_result From noreply at buildbot.pypy.org Sat Sep 26 08:02:05 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 26 Sep 2015 08:02:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue #2145: fix the logic for "float == large_int_but_not_a_long" on Message-ID: <20150926060206.0BBA41C1EB0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79847:680327d8b1a3 Date: 2015-09-26 08:01 +0200 http://bitbucket.org/pypy/pypy/changeset/680327d8b1a3/ Log: Issue #2145: fix the logic for "float == large_int_but_not_a_long" on 64-bit machines. It happened to work on x86-64 for example, but not on ppc64le. diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -4,6 +4,7 @@ from rpython.rlib import rarithmetic, rfloat from rpython.rlib.rarithmetic import LONG_BIT, intmask, ovfcheck_float_to_int +from rpython.rlib.rarithmetic import int_between from rpython.rlib.rbigint import rbigint from rpython.rlib.rfloat import ( DTSF_ADD_DOT_0, DTSF_STR_PRECISION, INFINITY, NAN, copysign, @@ -121,10 +122,11 @@ if space.isinstance_w(w_other, space.w_int): f1 = self.floatval i2 = space.int_w(w_other) - f2 = float(i2) - if LONG_BIT > 32 and int(f2) != i2: + # (double-)floats have always at least 48 bits of precision + if LONG_BIT > 32 and not int_between((-1)<<48, i2, 1<<48): res = do_compare_bigint(f1, rbigint.fromint(i2)) else: + f2 = float(i2) res = op(f1, f2) return space.newbool(res) if space.isinstance_w(w_other, space.w_long): diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -840,3 +840,12 @@ check(mod(0.0, -1.0), -0.0) check(mod(1e-100, -1.0), -1.0) check(mod(1.0, -1.0), -0.0) + + def test_equality_rounding(self): + i = int(2 ** 63 - 1) + f = float(i) # not enough precision, becomes 2.0 ** 63 + assert f == 2.0 ** 63 + assert i != f + assert f != i + assert long(i) != f + assert f != long(i) From noreply at buildbot.pypy.org Sat Sep 26 08:02:08 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 26 Sep 2015 08:02:08 +0200 (CEST) Subject: [pypy-commit] pypy ppc-updated-backend: Issue #2145: fix the logic for "float == large_int_but_not_a_long" on Message-ID: <20150926060208.3E8AF1C1EB0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: ppc-updated-backend Changeset: r79848:539582e91229 Date: 2015-09-26 08:01 +0200 http://bitbucket.org/pypy/pypy/changeset/539582e91229/ Log: Issue #2145: fix the logic for "float == large_int_but_not_a_long" on 64-bit machines. It happened to work on x86-64 for example, but not on ppc64le. diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -4,6 +4,7 @@ from rpython.rlib import rarithmetic, rfloat from rpython.rlib.rarithmetic import LONG_BIT, intmask, ovfcheck_float_to_int +from rpython.rlib.rarithmetic import int_between from rpython.rlib.rbigint import rbigint from rpython.rlib.rfloat import ( DTSF_ADD_DOT_0, DTSF_STR_PRECISION, INFINITY, NAN, copysign, @@ -121,10 +122,11 @@ if space.isinstance_w(w_other, space.w_int): f1 = self.floatval i2 = space.int_w(w_other) - f2 = float(i2) - if LONG_BIT > 32 and int(f2) != i2: + # (double-)floats have always at least 48 bits of precision + if LONG_BIT > 32 and not int_between((-1)<<48, i2, 1<<48): res = do_compare_bigint(f1, rbigint.fromint(i2)) else: + f2 = float(i2) res = op(f1, f2) return space.newbool(res) if space.isinstance_w(w_other, space.w_long): diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -840,3 +840,12 @@ check(mod(0.0, -1.0), -0.0) check(mod(1e-100, -1.0), -1.0) check(mod(1.0, -1.0), -0.0) + + def test_equality_rounding(self): + i = int(2 ** 63 - 1) + f = float(i) # not enough precision, becomes 2.0 ** 63 + assert f == 2.0 ** 63 + assert i != f + assert f != i + assert long(i) != f + assert f != long(i) From noreply at buildbot.pypy.org Sat Sep 26 09:00:09 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 26 Sep 2015 09:00:09 +0200 (CEST) Subject: [pypy-commit] cffi default: come on Py3 Message-ID: <20150926070009.55EDD1C12ED@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2275:56e881f76f18 Date: 2015-09-26 08:38 +0200 http://bitbucket.org/cffi/cffi/changeset/56e881f76f18/ Log: come on Py3 diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -879,7 +879,7 @@ # because they don't have any known C name. Check that they are # not partial (we can't complete or verify them!) and emit them # anonymously. - lst = self._struct_unions.items() + lst = list(self._struct_unions.items()) lst.sort(key=lambda tp_order: tp_order[1]) for tp, order in lst: if tp not in self._seen_struct_unions: From noreply at buildbot.pypy.org Sat Sep 26 09:00:11 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 26 Sep 2015 09:00:11 +0200 (CEST) Subject: [pypy-commit] cffi default: Issue #223 Message-ID: <20150926070011.549A61C12ED@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2276:a38f64ce5c4f Date: 2015-09-26 08:51 +0200 http://bitbucket.org/cffi/cffi/changeset/a38f64ce5c4f/ Log: Issue #223 Workaround: CPython 3.4 broke compatibility by adding tp_finalize, which in this case must be implemented too to avoid ordering issues at shutdown. (In <= 3.3 it works fine.) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1653,14 +1653,13 @@ static void _my_PyErr_WriteUnraisable(char *objdescr, PyObject *obj, char *extra_error_line); -static void cdatagcp_dealloc(CDataObject_gcp *cd) -{ - PyObject *result; - PyObject *destructor = cd->destructor; - PyObject *origobj = cd->origobj; - cdata_dealloc((CDataObject *)cd); + +static void gcp_finalize(PyObject *destructor, PyObject *origobj) +{ + /* NOTE: this decrements the reference count of the two arguments */ if (destructor != NULL) { + PyObject *result; PyObject *error_type, *error_value, *error_traceback; /* Save the current exception */ @@ -1679,7 +1678,27 @@ /* Restore the saved exception */ PyErr_Restore(error_type, error_value, error_traceback); } - Py_DECREF(origobj); + Py_XDECREF(origobj); +} + +#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ +static void cdatagcp_finalize(CDataObject_gcp *cd) +{ + PyObject *destructor = cd->destructor; + PyObject *origobj = cd->origobj; + cd->destructor = NULL; + cd->origobj = NULL; + gcp_finalize(destructor, origobj); +} +#endif + +static void cdatagcp_dealloc(CDataObject_gcp *cd) +{ + PyObject *destructor = cd->destructor; + PyObject *origobj = cd->origobj; + cdata_dealloc((CDataObject *)cd); + + gcp_finalize(destructor, origobj); } static int cdatagcp_traverse(CDataObject_gcp *cd, visitproc visit, void *arg) @@ -2814,6 +2833,9 @@ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ +#ifdef Py_TPFLAGS_HAVE_FINALIZE + | Py_TPFLAGS_HAVE_FINALIZE +#endif | Py_TPFLAGS_HAVE_GC, 0, /* tp_doc */ (traverseproc)cdatagcp_traverse, /* tp_traverse */ @@ -2826,6 +2848,25 @@ 0, /* tp_members */ 0, /* tp_getset */ &CData_Type, /* tp_base */ +#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* version_tag */ + (destructor)cdatagcp_finalize, /* tp_finalize */ +#endif }; /************************************************************/ From noreply at buildbot.pypy.org Sat Sep 26 09:00:13 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 26 Sep 2015 09:00:13 +0200 (CEST) Subject: [pypy-commit] cffi default: Test and fix: don't crash if there is a partial enum in the cdef() Message-ID: <20150926070013.4030C1C12ED@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2277:8228937d2afe Date: 2015-09-26 09:01 +0200 http://bitbucket.org/cffi/cffi/changeset/8228937d2afe/ Log: Test and fix: don't crash if there is a partial enum in the cdef() but we try to access an enum constant from a different enum. diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -631,13 +631,23 @@ # if not copied_enums: from . import model + error = None for key, tp in ffi._parser._declarations.items(): if not isinstance(tp, model.EnumType): continue - tp.check_not_partial() + try: + tp.check_not_partial() + except Exception as e: + error = e + continue for enumname, enumval in zip(tp.enumerators, tp.enumvalues): if enumname not in library.__dict__: library.__dict__[enumname] = enumval + if error is not None: + if name in library.__dict__: + return # ignore error, about a different enum + raise error + for key, val in ffi._parser._int_constants.items(): if key not in library.__dict__: library.__dict__[key] = val diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -930,8 +930,8 @@ ffi = FFI(backend=self.Backend()) ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };") lib = ffi.dlopen(None) + assert lib.B == 0 py.test.raises(VerificationMissing, getattr, lib, "A") - assert lib.B == 0 assert lib.C == 1 def test_array_of_struct(self): From noreply at buildbot.pypy.org Sat Sep 26 09:59:45 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Sat, 26 Sep 2015 09:59:45 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: test_zjit now passed the annotator to the rtyper Message-ID: <20150926075945.BD63B1C13F7@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79849:5d1e288a9250 Date: 2015-09-25 22:23 +0200 http://bitbucket.org/pypy/pypy/changeset/5d1e288a9250/ Log: test_zjit now passed the annotator to the rtyper diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -618,8 +618,8 @@ # the mapping might be wrong! if bridge_accum_info.vector_loc is not guard_accum_info.vector_loc: self.mov(guard_accum_info.vector_loc, bridge_accum_info.vector_loc) - bridge_accum_info = bridge_accum_info.prev - guard_accum_info = guard_accum_info.prev + bridge_accum_info = bridge_accum_info.next() + guard_accum_info = guard_accum_info.next() # register mapping is most likely NOT valid, thus remap it in this # short piece of assembler diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -318,6 +318,7 @@ def locs_for_fail(self, guard_op): faillocs = [self.loc(arg) for arg in guard_op.getfailargs()] descr = guard_op.getdescr() + assert isinstance(descr, ResumeGuardDescr) if descr and descr.rd_accum_list: accuminfo = descr.rd_accum_list while accuminfo: diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -15,7 +15,8 @@ TargetToken, AbstractFailDescr, ConstInt) from rpython.jit.metainterp import history, jitexc from rpython.jit.metainterp.optimize import InvalidLoop -from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader +from rpython.jit.metainterp.resume import (NUMBERING, PENDINGFIELDSP, + ResumeDataDirectReader, AccumInfo) from rpython.jit.codewriter import heaptracker, longlong def giveup(): @@ -679,8 +680,7 @@ class ResumeGuardDescr(ResumeDescr): _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals', - 'rd_frame_info_list', 'rd_pendingfields', 'rd_accum_list', - 'status') + 'rd_frame_info_list', 'rd_pendingfields', 'status') rd_numb = lltype.nullptr(NUMBERING) rd_count = 0 @@ -688,7 +688,6 @@ rd_virtuals = None rd_frame_info_list = None rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) - rd_accum_list = None status = r_uint(0) @@ -702,6 +701,8 @@ self.rd_numb = other.rd_numb if other.rd_accum_list: self.rd_accum_list = other.rd_accum_list.clone() + else: + other.rd_accum_list = None # we don't copy status ST_BUSY_FLAG = 0x01 # if set, busy tracing from the guard @@ -850,6 +851,10 @@ def exits_early(self): return True + def attach_accum_info(self, pos, operator, arg, loc): + self.rd_accum_list = \ + AccumInfo(self.rd_accum_list, pos, operator, arg, loc) + class ResumeGuardNonnullDescr(ResumeGuardDescr): guard_opnum = rop.GUARD_NONNULL diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -148,6 +148,8 @@ _attrs_ = ('adr_jump_offset', 'rd_locs', 'rd_loop_token', 'rd_accum_list') + rd_accum_list = None + def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): raise NotImplementedError def compile_and_attach(self, metainterp, new_loop, orig_inputargs): diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -446,7 +446,8 @@ if vecop: args[index] = vecop return vecop - vecop = OpHelpers.create_vec_expand(arg, op.bytesize, op.signed, pack.numops()) + left = pack.leftmost() + vecop = OpHelpers.create_vec_expand(arg, left.bytesize, left.signed, pack.numops()) ops.append(vecop) if variables is not None: variables.append(vecop) @@ -549,9 +550,10 @@ continue accum = self.accumulation.get(arg, None) if accum: + from rpython.jit.metainterp.compile import ResumeGuardDescr assert isinstance(accum, AccumPack) - descr.rd_accum_list = AccumInfo(descr.rd_accum_list, i, - accum.operator, arg, None) + assert isinstance(descr, ResumeGuardDescr) + descr.attach_accum_info(i, accum.operator, arg, None) seed = accum.getleftmostseed() failargs[i] = self.renamer.rename_map.get(seed, seed) From noreply at buildbot.pypy.org Sat Sep 26 09:59:47 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Sat, 26 Sep 2015 09:59:47 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: translation issues, zero_deps guards would produce cycle, remove them Message-ID: <20150926075947.CEABB1C13F7@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79850:9236f6c98306 Date: 2015-09-26 10:00 +0200 http://bitbucket.org/pypy/pypy/changeset/9236f6c98306/ Log: translation issues, zero_deps guards would produce cycle, remove them diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py b/rpython/jit/metainterp/optimizeopt/dependency.py --- a/rpython/jit/metainterp/optimizeopt/dependency.py +++ b/rpython/jit/metainterp/optimizeopt/dependency.py @@ -62,6 +62,9 @@ return None return self.path[-1] + def first(self): + return self.path[0] + def is_always_pure(self, exclude_first=False, exclude_last=False): last = len(self.path)-1 count = len(self.path) @@ -596,19 +599,6 @@ # the label operation defines all operations at the # beginning of the loop - # TODO if op.getopnum() == rop.LABEL and i != jump_pos: - # node.setpriority(100) - # label_pos = i - # for arg in op.getarglist(): - # tracker.define(arg, node) - # continue # prevent adding edge to the label itself - #elif node.is_guard_early_exit(): - # label_node = self.nodes[label_pos] - # label_node.edge_to(node,None,label='L->EE') - # for arg in label_node.getoperation().getarglist(): - # tracker.define(arg, node) - # continue - intformod.inspect_operation(op,node) # definition of a new variable if op.type != 'v': diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -1235,6 +1235,7 @@ self.assert_equal(trace, trace_opt) def test_axis_sum(self): + # TODO trace = """ [i1, p10, i11, p8, i12, p3, p4, p13, i14, i15, p6, p9, i16, i17, i18, i19, i20, i21, i22, i23] f24 = raw_load_f(i16, i12, descr=floatarraydescr) @@ -1257,11 +1258,8 @@ guard_false(i39) [i1, p9, p8, p6, p4, p3, i33, i38, None, None, i26, i11, None, p13, None, None, p10] jump(i1, p10, i11, p8, i26, p3, p4, p13, i33, i38, p6, p9, i16, i17, i18, i19, i20, i21, i22, i23) """ - try: - self.vectorize(self.parse_loop(trace)) - py.test.fail("axis sum is not profitable") - except NotAProfitableLoop: - pass + loop = self.parse_loop(trace) + self.vectorize(loop) def test_cast_1(self): # TODO diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -103,7 +103,9 @@ loop_info, loop_ops, jitcell_token=None): """ Enter the world of SIMD. Bails if it cannot transform the trace. """ user_code = not jitdriver_sd.vec and warmstate.vec_all - loop = VectorLoop(loop_info.label_op, loop_ops[1:-1], loop_ops[-1]) + e = len(loop_ops)-1 + assert e > 0 + loop = VectorLoop(loop_info.label_op, loop_ops[1:e], loop_ops[-1]) if user_code and user_loop_bail_fast_path(loop, warmstate): return loop_info, loop_ops # the original loop (output of optimize_unroll) @@ -515,6 +517,8 @@ modify_later = [] last_prev_node = None valid = True + if guard_node in zero_deps: + del zero_deps[guard_node] for prev_dep in guard_node.depends(): prev_node = prev_dep.to if prev_dep.is_failarg(): @@ -551,6 +555,7 @@ self.mark_guard(guard_node, loop) for node in zero_deps.keys(): assert not node.is_imaginary() + print "edge to", node earlyexit.edge_to(node) if one_valid: return graph diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -177,6 +177,7 @@ def reset_jit(): """Helper for some tests (see micronumpy/test/test_zjit.py)""" + from rpython.jit.metainterp import counter reset_stats() pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear() pyjitpl._warmrunnerdesc.jitcounter._clear_all() From noreply at buildbot.pypy.org Sat Sep 26 12:48:34 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 26 Sep 2015 12:48:34 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: a fix with an explanation Message-ID: <20150926104835.0C4451C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79851:c2366bb48cc4 Date: 2015-09-26 12:44 +0200 http://bitbucket.org/pypy/pypy/changeset/c2366bb48cc4/ Log: a fix with an explanation 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 @@ -583,10 +583,13 @@ self.exception_might_have_happened = True if ((op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() or op.is_ovf()) and - not self.is_call_pure_pure_canraise(op)): + not self.is_call_pure_pure_canraise(op) and + not op.getopnum() == rop.ENTER_PORTAL_FRAME): + # we can't share across ENTER_PORTAL_FRAME because if we later + # change the decision of inlining into that portal frame, we + # won't follow the same path through blackhole pass else: - #assert self.origin_jitcode is None self._last_guard_op = None self._really_emitted_operation = op self._newoperations.append(op) From noreply at buildbot.pypy.org Sat Sep 26 12:48:37 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 26 Sep 2015 12:48:37 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: count shared guards Message-ID: <20150926104837.482D81C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79852:10c6022aa88e Date: 2015-09-26 12:48 +0200 http://bitbucket.org/pypy/pypy/changeset/10c6022aa88e/ Log: count shared guards diff --git a/rpython/jit/metainterp/jitprof.py b/rpython/jit/metainterp/jitprof.py --- a/rpython/jit/metainterp/jitprof.py +++ b/rpython/jit/metainterp/jitprof.py @@ -141,6 +141,7 @@ self._print_intline("recorded ops", cnt[Counters.RECORDED_OPS]) self._print_intline(" calls", calls) self._print_intline("guards", cnt[Counters.GUARDS]) + self._print_intline("guards_shared", cnt[Counters.GUARDS_SHARED]) self._print_intline("opt ops", cnt[Counters.OPT_OPS]) self._print_intline("opt guards", cnt[Counters.OPT_GUARDS]) self._print_intline("forcings", cnt[Counters.OPT_FORCINGS]) 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 @@ -596,8 +596,11 @@ def emit_guard_operation(self, op, pendingfields): guard_op = self.replace_op_with(op, op.getopnum()) + opnum = guard_op.getopnum() if (self._last_guard_op and guard_op.getdescr() is None and - guard_op.getopnum() != rop.GUARD_VALUE): + opnum != rop.GUARD_VALUE): + self.metainterp_sd.profiler.count_ops(opnum, + jitprof.Counters.GUARDS_SHARED) op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -1150,6 +1150,7 @@ OPS RECORDED_OPS GUARDS + GUARDS_SHARED OPT_OPS OPT_GUARDS OPT_FORCINGS From noreply at buildbot.pypy.org Sat Sep 26 13:09:54 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 26 Sep 2015 13:09:54 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: make it cleaner Message-ID: <20150926110954.3F62A1C0933@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79853:ac8ca7d0b4c5 Date: 2015-09-26 13:09 +0200 http://bitbucket.org/pypy/pypy/changeset/ac8ca7d0b4c5/ Log: make it cleaner diff --git a/rpython/jit/metainterp/jitprof.py b/rpython/jit/metainterp/jitprof.py --- a/rpython/jit/metainterp/jitprof.py +++ b/rpython/jit/metainterp/jitprof.py @@ -141,9 +141,9 @@ self._print_intline("recorded ops", cnt[Counters.RECORDED_OPS]) self._print_intline(" calls", calls) self._print_intline("guards", cnt[Counters.GUARDS]) - self._print_intline("guards_shared", cnt[Counters.GUARDS_SHARED]) self._print_intline("opt ops", cnt[Counters.OPT_OPS]) self._print_intline("opt guards", cnt[Counters.OPT_GUARDS]) + self._print_intline("opt guards shared", cnt[Counters.OPT_GUARDS_SHARED]) self._print_intline("forcings", cnt[Counters.OPT_FORCINGS]) self._print_intline("abort: trace too long", cnt[Counters.ABORT_TOO_LONG]) 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 @@ -600,7 +600,7 @@ if (self._last_guard_op and guard_op.getdescr() is None and opnum != rop.GUARD_VALUE): self.metainterp_sd.profiler.count_ops(opnum, - jitprof.Counters.GUARDS_SHARED) + jitprof.Counters.OPT_GUARDS_SHARED) op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: @@ -722,8 +722,6 @@ raise AssertionError("uh?") newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr) return newop - # a real GUARD_VALUE. Make it use one counter per value. - descr.make_a_counter_per_value(op) return op def optimize_default(self, op): diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -1150,9 +1150,9 @@ OPS RECORDED_OPS GUARDS - GUARDS_SHARED OPT_OPS OPT_GUARDS + OPT_GUARDS_SHARED OPT_FORCINGS ABORT_TOO_LONG ABORT_BRIDGE From noreply at buildbot.pypy.org Sat Sep 26 13:35:50 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 26 Sep 2015 13:35:50 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: implement fishing guard_value value directly from a jitframe, hence removing the need of failargs storing the argument, hence we can share stuff across guard_value Message-ID: <20150926113550.E46681C12ED@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79854:3fb386e048dd Date: 2015-09-26 13:35 +0200 http://bitbucket.org/pypy/pypy/changeset/3fb386e048dd/ Log: implement fishing guard_value value directly from a jitframe, hence removing the need of failargs storing the argument, hence we can share stuff across guard_value diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -671,6 +671,8 @@ a0, a1 = boxes imm_a1 = check_imm_box(a1) l0 = self.make_sure_var_in_reg(a0, boxes) + op.getdescr().make_a_counter_per_value(op, + self.cpu.all_reg_indexes[l0.value]) if not imm_a1: l1 = self.make_sure_var_in_reg(a1, boxes) else: 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 @@ -40,6 +40,10 @@ self.inputargs = map(mapping, inputargs) self.operations = [] for op in operations: + if op.getopnum() == rop.GUARD_VALUE: + # we don't care about the value 13 here, because we gonna + # fish it from the extra slot on frame anyway + op.getdescr().make_a_counter_per_value(op, 13) if op.getdescr() is not None: if op.is_guard() or op.getopnum() == rop.FINISH: newdescr = op.getdescr() @@ -372,6 +376,18 @@ except ExecutionFinished, e: return e.deadframe + def get_value_direct(self, deadframe, tp, index): + v = deadframe._extra_value + if tp == 'i': + assert lltype.typeOf(v) == lltype.Signed + elif tp == 'r': + assert lltype.typeOf(v) == llmemory.GCREF + elif tp == 'f': + assert lltype.typeOf(v) == longlong.FLOATSTORAGE + else: + assert False + return v + def get_int_value(self, deadframe, index): v = deadframe._values[index] assert lltype.typeOf(v) == lltype.Signed @@ -775,11 +791,13 @@ _TYPE = llmemory.GCREF def __init__(self, latest_descr, values, - last_exception=None, saved_data=None): + last_exception=None, saved_data=None, + extra_value=None): self._latest_descr = latest_descr self._values = values self._last_exception = last_exception self._saved_data = saved_data + self._extra_value = extra_value class LLFrame(object): @@ -872,7 +890,7 @@ # ----------------------------------------------------- - def fail_guard(self, descr, saved_data=None): + def fail_guard(self, descr, saved_data=None, extra_value=None): values = [] for box in self.current_op.getfailargs(): if box is not None: @@ -887,7 +905,7 @@ else: raise ExecutionFinished(LLDeadFrame(descr, values, self.last_exception, - saved_data)) + saved_data, extra_value)) def execute_force_spill(self, _, arg): pass @@ -909,7 +927,7 @@ def execute_guard_value(self, descr, arg1, arg2): if arg1 != arg2: - self.fail_guard(descr) + self.fail_guard(descr, extra_value=arg1) def execute_guard_nonnull(self, descr, arg): if not arg: diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -389,20 +389,40 @@ descr = self.get_latest_descr(deadframe) return rffi.cast(lltype.Signed, descr.rd_locs[index]) * WORD + @specialize.arg(2) + def get_value_direct(self, deadframe, tp, index): + if tp == 'i': + return self.get_int_value_direct(deadframe, index * WORD) + elif tp == 'r': + return self.get_ref_value_direct(deadframe, index * WORD) + elif tp == 'f': + return self.get_float_value_direct(deadframe, index * WORD) + else: + assert False + def get_int_value(self, deadframe, index): pos = self._decode_pos(deadframe, index) + return self.get_int_value_direct(deadframe, pos) + + def get_int_value_direct(self, deadframe, pos): descr = self.gc_ll_descr.getframedescrs(self).arraydescr ofs = self.unpack_arraydescr(descr) return self.read_int_at_mem(deadframe, pos + ofs, WORD, 1) def get_ref_value(self, deadframe, index): pos = self._decode_pos(deadframe, index) + return self.get_ref_value_direct(deadframe, pos) + + def get_ref_value_direct(self, deadframe, pos): descr = self.gc_ll_descr.getframedescrs(self).arraydescr ofs = self.unpack_arraydescr(descr) return self.read_ref_at_mem(deadframe, pos + ofs) def get_float_value(self, deadframe, index): pos = self._decode_pos(deadframe, index) + return self.get_float_value_direct(deadframe, pos) + + def get_float_value_direct(self, deadframe, pos): descr = self.gc_ll_descr.getframedescrs(self).arraydescr ofs = self.unpack_arraydescr(descr) return self.read_float_at_mem(deadframe, pos + ofs) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -424,6 +424,8 @@ def consider_guard_value(self, op): x = self.make_sure_var_in_reg(op.getarg(0)) + loc = self.assembler.cpu.all_reg_indexes[x.value] + op.getdescr().make_a_counter_per_value(op, loc) y = self.loc(op.getarg(1)) self.perform_guard(op, [x, y], None) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -777,12 +777,15 @@ # fetch the actual value of the guard_value, possibly turning # it to an integer if typetag == self.TY_INT: - intval = metainterp_sd.cpu.get_int_value(deadframe, index) + intval = metainterp_sd.cpu.get_value_direct(deadframe, 'i', + index) elif typetag == self.TY_REF: - refval = metainterp_sd.cpu.get_ref_value(deadframe, index) + refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r', + index) intval = lltype.cast_ptr_to_int(refval) elif typetag == self.TY_FLOAT: - floatval = metainterp_sd.cpu.get_float_value(deadframe, index) + floatval = metainterp_sd.cpu.get_value_direct(deadframe, 'f', + index) intval = longlong.gethash_fast(floatval) else: assert 0, typetag @@ -798,11 +801,6 @@ increment = jitdriver_sd.warmstate.increment_trace_eagerness return jitcounter.tick(hash, increment) - def get_index_of_guard_value(self): - if (self.status & self.ST_TYPE_MASK) == 0: - return -1 - return intmask(self.status >> self.ST_SHIFT) - def start_compiling(self): # start tracing and compiling from this guard. self.status |= self.ST_BUSY_FLAG @@ -829,23 +827,18 @@ new_loop.original_jitcell_token, metainterp.box_names_memo) - def make_a_counter_per_value(self, guard_value_op): + def make_a_counter_per_value(self, guard_value_op, index): assert guard_value_op.getopnum() == rop.GUARD_VALUE box = guard_value_op.getarg(0) - try: - i = guard_value_op.getfailargs().index(box) - except ValueError: - return # xxx probably very rare + if box.type == history.INT: + ty = self.TY_INT + elif box.type == history.REF: + ty = self.TY_REF + elif box.type == history.FLOAT: + ty = self.TY_FLOAT else: - if box.type == history.INT: - ty = self.TY_INT - elif box.type == history.REF: - ty = self.TY_REF - elif box.type == history.FLOAT: - ty = self.TY_FLOAT - else: - assert 0, box.type - self.status = ty | (r_uint(i) << self.ST_SHIFT) + assert 0, box.type + self.status = ty | (r_uint(index) << self.ST_SHIFT) class ResumeGuardExcDescr(ResumeGuardDescr): pass 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 @@ -597,8 +597,7 @@ def emit_guard_operation(self, op, pendingfields): guard_op = self.replace_op_with(op, op.getopnum()) opnum = guard_op.getopnum() - if (self._last_guard_op and guard_op.getdescr() is None and - opnum != rop.GUARD_VALUE): + if (self._last_guard_op and guard_op.getdescr() is None): self.metainterp_sd.profiler.count_ops(opnum, jitprof.Counters.OPT_GUARDS_SHARED) op = self._copy_resume_data_from(guard_op, 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 @@ -1480,16 +1480,6 @@ res = self.meta_interp(f, [299], listops=True) assert res == f(299) self.check_resops(guard_class=4, guard_value=6) - # - # The original 'guard_class' is rewritten to be directly 'guard_value'. - # Check that this rewrite does not interfere with the descr, which - # should be a full-fledged multivalued 'guard_value' descr. - if self.basic: - for loop in get_stats().get_all_loops(): - for op in loop.get_operations(): - if op.getopname() == "guard_value": - descr = op.getdescr() - assert descr.get_index_of_guard_value() >= 0 def test_merge_guardnonnull_guardclass(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'l']) From noreply at buildbot.pypy.org Sun Sep 27 02:02:51 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 27 Sep 2015 02:02:51 +0200 (CEST) Subject: [pypy-commit] pypy numpy-ctypes: Close branch before merging Message-ID: <20150927000251.8142E1C0933@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: numpy-ctypes Changeset: r79855:d68b839b87f1 Date: 2015-09-27 01:00 +0100 http://bitbucket.org/pypy/pypy/changeset/d68b839b87f1/ Log: Close branch before merging From noreply at buildbot.pypy.org Sun Sep 27 02:02:53 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 27 Sep 2015 02:02:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge branch 'numpy-ctypes' Message-ID: <20150927000253.CAD6B1C1311@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Changeset: r79856:a0d630bd2618 Date: 2015-09-27 01:01 +0100 http://bitbucket.org/pypy/pypy/changeset/a0d630bd2618/ Log: Merge branch 'numpy-ctypes' Add support for ndarray.ctypes property diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -747,8 +747,12 @@ return out def descr_get_ctypes(self, space): - raise OperationError(space.w_NotImplementedError, space.wrap( - "ctypes not implemented yet")) + w_result = space.appexec([self], """(arr): + from numpy.core import _internal + p_data = arr.__array_interface__['data'][0] + return _internal._ctypes(arr, p_data) + """) + return w_result def buffer_w(self, space, flags): return self.implementation.get_buffer(space, True) From noreply at buildbot.pypy.org Sun Sep 27 02:02:55 2015 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 27 Sep 2015 02:02:55 +0200 (CEST) Subject: [pypy-commit] pypy default: document branch Message-ID: <20150927000255.E2F371C13F7@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Changeset: r79857:b606e35d99a1 Date: 2015-09-27 01:03 +0100 http://bitbucket.org/pypy/pypy/changeset/b606e35d99a1/ Log: document branch 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 @@ -39,3 +39,7 @@ .. branch: shadowstack-no-move-2 Issue #2141: fix a crash on Windows and OS/X and ARM when running at least 20 threads. + +.. branch: numpy-ctypes + +Add support for ndarray.ctypes property. From noreply at buildbot.pypy.org Sun Sep 27 09:42:55 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 09:42:55 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: make the crash more explicit Message-ID: <20150927074255.064CC1C0162@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79858:08a671c04e1f Date: 2015-09-27 09:43 +0200 http://bitbucket.org/pypy/pypy/changeset/08a671c04e1f/ Log: make the crash more explicit 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 @@ -529,6 +529,10 @@ if extra_jump: self.first_optimization.propagate_forward(ops[-1]) self.resumedata_memo.update_counters(self.metainterp_sd.profiler) + + if self.origin_jitcode is not None: + raise Exception("Was looking for guard never foudnd it") + return (BasicLoopInfo(newargs, self.quasi_immutable_deps), self._newoperations) From noreply at buildbot.pypy.org Sun Sep 27 09:49:24 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 09:49:24 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix (this should fix test_pypy_c.test_generators) Message-ID: <20150927074924.0FE131C0162@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79859:afce8682985f Date: 2015-09-27 09:49 +0200 http://bitbucket.org/pypy/pypy/changeset/afce8682985f/ Log: Test and fix (this should fix test_pypy_c.test_generators) diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -72,7 +72,7 @@ def do_setfield(self, optheap, op): # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structinfo = optheap.ensure_ptr_info_arg0(op) - arg1 = optheap.get_box_replacement(op.getarg(1)) + arg1 = optheap.get_box_replacement(self._getvalue(op)) if self.possible_aliasing(optheap, structinfo): self.force_lazy_setfield(optheap, op.getdescr()) assert not self.possible_aliasing(optheap, structinfo) 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 @@ -5993,5 +5993,22 @@ """ self.optimize_loop(ops, expected) + def test_remove_multiple_setarrayitems(self): + ops = """ + [p0, i1] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) + guard_value(i1, 42) [] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) # remove this + finish() + """ + expected = """ + [p0, i1] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) + guard_value(i1, 42) [] + finish() + """ + self.optimize_loop(ops, expected) + + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass From noreply at buildbot.pypy.org Sun Sep 27 11:57:28 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 27 Sep 2015 11:57:28 +0200 (CEST) Subject: [pypy-commit] pypy default: add failing tests that pass with upstream -A Message-ID: <20150927095728.2D30A1C1149@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79860:5c67d551e0c5 Date: 2015-09-27 02:35 +0300 http://bitbucket.org/pypy/pypy/changeset/5c67d551e0c5/ Log: add failing tests that pass with upstream -A diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -2218,7 +2218,7 @@ assert _weakref.ref(a) def test_astype(self): - from numpy import array, arange + from numpy import array, arange, empty b = array(1).astype(float) assert b == 1 assert b.dtype == float @@ -2273,14 +2273,36 @@ b = a.astype('f4', order='C', copy=False) assert a is b + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + c = b[:, :2, :] + d = c.swapaxes(1, -1) + e = d.astype('complex128') + assert e.shape == (3, 3, 2) + assert e.strides == (96, 16, 48) + assert (e.real == d).all() + def test_base(self): - from numpy import array + from numpy import array, empty assert array(1).base is None assert array([1, 2]).base is None a = array([1, 2, 3, 4]) b = a[::2] assert b.base is a + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + assert b.base.base is None + c = b[:, :2, :] + d = c.swapaxes(1, -1) + assert c.base.base is None + assert d.base.base is None + assert d.shape == (3, 3, 2) + assert d.__array_interface__['data'][0] == \ + a.__array_interface__['data'][0] + a.strides[0] * 2 + def test_byteswap(self): from numpy import array From noreply at buildbot.pypy.org Sun Sep 27 11:57:30 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 27 Sep 2015 11:57:30 +0200 (CEST) Subject: [pypy-commit] pypy default: use timsort in astype to ascertain stride pattern, but create a continuous array Message-ID: <20150927095730.42AC01C1149@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79861:1bba158521bb Date: 2015-09-27 02:36 +0300 http://bitbucket.org/pypy/pypy/changeset/1bba158521bb/ Log: use timsort in astype to ascertain stride pattern, but create a continuous array diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -354,12 +355,17 @@ elif order != self.order: t_strides, backstrides = calc_strides(shape, dtype, order) else: - mins = strides[0] + def arg_lt(a, b): + return strides[a] < strides[b] + ArgSort=make_timsort_class(lt=arg_lt) + indx_array = range(len(strides)) + ArgSort(indx_array).sort() t_elsize = dtype.elsize - for s in strides: - if s < mins: - mins = s - t_strides = [s * t_elsize / mins for s in strides] + t_strides = strides[:] + base = dtype.elsize + for i in indx_array: + t_strides[i] = base + base *= shape[i] backstrides = calc_backstrides(t_strides, shape) impl = ConcreteArray(shape, dtype, order, t_strides, backstrides) loop.setslice(space, impl.get_shape(), impl, self) From noreply at buildbot.pypy.org Sun Sep 27 11:57:32 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 27 Sep 2015 11:57:32 +0200 (CEST) Subject: [pypy-commit] pypy default: do not chain ndarray.base; ensure ndarray.base.base is None Message-ID: <20150927095732.6D6BB1C1149@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79862:399217ef3933 Date: 2015-09-27 02:38 +0300 http://bitbucket.org/pypy/pypy/changeset/399217ef3933/ Log: do not chain ndarray.base; ensure ndarray.base.base is None diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -557,6 +557,11 @@ self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) except OverflowError: raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") + while orig_arr is not None: + assert isinstance(orig_arr, W_NDimArray) + if orig_arr.implementation.base() is None: + break + orig_arr = orig_arr.implementation.base() self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED From noreply at buildbot.pypy.org Sun Sep 27 11:57:34 2015 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 27 Sep 2015 11:57:34 +0200 (CEST) Subject: [pypy-commit] pypy default: fix translation - closure -> class Message-ID: <20150927095734.873111C1149@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79863:403ce2521b92 Date: 2015-09-27 08:52 +0300 http://bitbucket.org/pypy/pypy/changeset/403ce2521b92/ Log: fix translation - closure -> class diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -18,6 +18,19 @@ is_f_contiguous) from rpython.rlib.objectmodel import keepalive_until_here +TimSort = make_timsort_class() +class StrideSort(TimSort): + ''' + argsort (return the indices to sort) a list of strides + ''' + def __init__(self, rangelist, strides): + self.strides = strides + TimSort.__init__(self, rangelist) + + def lt(self, a, b): + return self.strides[a] < self.strides[b] + + class BaseConcreteArray(object): _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]', 'strides[*]', 'backstrides[*]', 'order', 'gcstruct', @@ -355,11 +368,9 @@ elif order != self.order: t_strides, backstrides = calc_strides(shape, dtype, order) else: - def arg_lt(a, b): - return strides[a] < strides[b] - ArgSort=make_timsort_class(lt=arg_lt) indx_array = range(len(strides)) - ArgSort(indx_array).sort() + list_sorter = StrideSort(indx_array, strides) + list_sorter.sort() t_elsize = dtype.elsize t_strides = strides[:] base = dtype.elsize From noreply at buildbot.pypy.org Sun Sep 27 13:09:44 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 13:09:44 +0200 (CEST) Subject: [pypy-commit] cffi default: The symbol "myprintf" seems to conflict on some machines. Use a Message-ID: <20150927110944.6EE661C023F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2278:fd7a1817301d Date: 2015-09-27 13:10 +0200 http://bitbucket.org/cffi/cffi/changeset/fd7a1817301d/ Log: The symbol "myprintf" seems to conflict on some machines. Use a different name in this test. diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -1635,11 +1635,11 @@ def test_FILE_stored_explicitly(): ffi = FFI() - ffi.cdef("int myprintf(const char *, int); FILE *myfile;") + ffi.cdef("int myprintf11(const char *, int); FILE *myfile;") lib = ffi.verify(""" #include FILE *myfile; - int myprintf(const char *out, int value) { + int myprintf11(const char *out, int value) { return fprintf(myfile, out, value); } """) @@ -1649,7 +1649,7 @@ lib.myfile = ffi.cast("FILE *", fw1) # fw1.write(b"X") - r = lib.myprintf(b"hello, %d!\n", ffi.cast("int", 42)) + r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42)) fw1.close() assert r == len("hello, 42!\n") # From noreply at buildbot.pypy.org Sun Sep 27 13:11:32 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 13:11:32 +0200 (CEST) Subject: [pypy-commit] cffi default: More of the same Message-ID: <20150927111132.87A4A1C1149@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2279:b25fef6ab1f1 Date: 2015-09-27 13:12 +0200 http://bitbucket.org/cffi/cffi/changeset/b25fef6ab1f1/ Log: More of the same diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -1622,11 +1622,11 @@ def test_FILE_stored_explicitly(): ffi = FFI() - ffi.cdef("int myprintf(const char *, int); FILE *myfile;") + ffi.cdef("int myprintf11(const char *, int); FILE *myfile;") lib = ffi.verify(""" #include FILE *myfile; - int myprintf(const char *out, int value) { + int myprintf11(const char *out, int value) { return fprintf(myfile, out, value); } """) @@ -1636,7 +1636,7 @@ lib.myfile = ffi.cast("FILE *", fw1) # fw1.write(b"X") - r = lib.myprintf(b"hello, %d!\n", ffi.cast("int", 42)) + r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42)) fw1.close() assert r == len("hello, 42!\n") # From noreply at buildbot.pypy.org Sun Sep 27 17:11:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 17:11:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Obscure test, but I've seen something like that occur. In general we Message-ID: <20150927151146.D6EE91C04C6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79864:bc6376d1c390 Date: 2015-09-27 17:12 +0200 http://bitbucket.org/pypy/pypy/changeset/bc6376d1c390/ Log: Obscure test, but I've seen something like that occur. In general we need to review all usages of get_forwarded() on an int box: this could return an unexpected RawPtrInfo. 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 @@ -8902,5 +8902,15 @@ """ self.optimize_loop(ops, expected) + def test_raw_buffer_ptr_info_intbounds(self): + ops = """ + [i1] + i2 = call_i('malloc', 10, descr=raw_malloc_descr) + guard_value(i2, 12345) [] + jump(i2) + """ + self.optimize_loop(ops, ops) + + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass From noreply at buildbot.pypy.org Sun Sep 27 17:29:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 17:29:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Test fix Message-ID: <20150927152937.015CD1C1149@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79865:644a9163d222 Date: 2015-09-27 17:29 +0200 http://bitbucket.org/pypy/pypy/changeset/644a9163d222/ Log: Test fix 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 @@ -3,7 +3,7 @@ from rpython.jit.metainterp.logger import LogOperations from rpython.jit.metainterp.history import Const, ConstInt, REF, ConstPtr from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\ - ConstIntBound, MININT, MAXINT + ConstIntBound, MININT, MAXINT, IntUnbounded from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.resoperation import rop, AbstractResOp, GuardResOp,\ OpHelpers, ResOperation @@ -57,9 +57,11 @@ if isinstance(op, ConstInt): return ConstIntBound(op.getint()) fw = op.get_forwarded() - if isinstance(fw, IntBound): - return fw - assert fw is None + if fw is not None: + if isinstance(fw, IntBound): + return fw + # rare case: fw might be a RawBufferPtrInfo + return IntUnbounded() assert op.type == 'i' intbound = IntBound(MININT, MAXINT) op.set_forwarded(intbound) @@ -72,7 +74,8 @@ return cur = op.get_forwarded() if cur is not None: - cur.intersect(bound) + if isinstance(cur, IntBound): + cur.intersect(bound) else: op.set_forwarded(bound) @@ -404,7 +407,8 @@ box = self.get_box_replacement(box) if not we_are_translated(): # safety-check if (box.get_forwarded() is not None and - isinstance(constbox, ConstInt)): + isinstance(constbox, ConstInt) and + not isinstance(box.get_forwarded(), info.AbstractRawPtrInfo)): assert box.get_forwarded().contains(constbox.getint()) if box.is_constant(): return 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 @@ -8902,12 +8902,12 @@ """ self.optimize_loop(ops, expected) - def test_raw_buffer_ptr_info_intbounds(self): - ops = """ - [i1] + def test_raw_buffer_ptr_info_intbounds_bug(self): + ops = """ + [] i2 = call_i('malloc', 10, descr=raw_malloc_descr) guard_value(i2, 12345) [] - jump(i2) + jump() """ self.optimize_loop(ops, ops) From noreply at buildbot.pypy.org Sun Sep 27 17:32:01 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 17:32:01 +0200 (CEST) Subject: [pypy-commit] pypy default: Confusion: RPython assumes everywhere (including in the JIT) that Message-ID: <20150927153201.901B91C1149@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79866:ea08d9ade6c4 Date: 2015-09-27 16:35 +0100 http://bitbucket.org/pypy/pypy/changeset/ea08d9ade6c4/ Log: Confusion: RPython assumes everywhere (including in the JIT) that lltype.UniChar is unsigned. But that's wrong: the C backend translates it to 'wchar_t', which is sometimes a signed 32-bit integer. Notable result: when RPython code starts to run with the JIT, the sign of UniChars suddenly appears to change. It should be fixed everywhere in RPython. For now, a simple workaround to fix one case. diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -125,12 +125,24 @@ cdata[0] = value +# XXX explicitly use an integer type instead of lltype.UniChar here, +# because for now the latter is defined as unsigned by RPython (even +# though it may be signed when 'wchar_t' is written to C). +WCHAR_INT = {(2, False): rffi.USHORT, + (4, False): rffi.UINT, + (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar), rffi.r_wchar_t.SIGN] +WCHAR_INTP = rffi.CArrayPtr(WCHAR_INT) + class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar): _attrs_ = [] + if rffi.r_wchar_t.SIGN: + def write_raw_integer_data(self, w_cdata, value): + w_cdata.write_raw_signed_data(value) + def cast_to_int(self, cdata): - unichardata = rffi.cast(rffi.CWCHARP, cdata) - return self.space.wrap(ord(unichardata[0])) + unichardata = rffi.cast(WCHAR_INTP, cdata) + return self.space.wrap(unichardata[0]) def convert_to_object(self, cdata): unichardata = rffi.cast(rffi.CWCHARP, cdata) 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 @@ -4319,3 +4319,15 @@ self.meta_interp(allfuncs, [9, 2000]) + + def test_unichar_might_be_signed(self): + py.test.skip("wchar_t is sometimes a signed 32-bit integer type, " + "but RPython inteprets it as unsigned (but still " + "translates to wchar_t, so can create confusion)") + def f(x): + return rffi.cast(lltype.Signed, rffi.cast(lltype.UniChar, x)) + res = self.interp_operations(f, [-1]) + if rffi.r_wchar_t.SIGN: + assert res == -1 + else: + assert res == 2 ** 16 - 1 or res == 2 ** 32 - 1 From noreply at buildbot.pypy.org Sun Sep 27 17:33:26 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 17:33:26 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20150927153326.BC53C1C13F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r640:74b141147652 Date: 2015-09-27 17:34 +0200 http://bitbucket.org/pypy/pypy.org/changeset/74b141147652/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -15,7 +15,7 @@ - $60561 of $105000 (57.7%) + $60580 of $105000 (57.7%)
    @@ -23,7 +23,7 @@
  • diff --git a/don4.html b/don4.html --- a/don4.html +++ b/don4.html @@ -9,7 +9,7 @@ @@ -17,7 +17,7 @@ 2nd call: - $29431 of $80000 (36.8%) + $29481 of $80000 (36.9%)
    @@ -25,7 +25,7 @@
  • From noreply at buildbot.pypy.org Sun Sep 27 18:03:32 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 18:03:32 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: merge default Message-ID: <20150927160332.EE46C1C1EA1@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79867:303ed67a871d Date: 2015-09-27 18:03 +0200 http://bitbucket.org/pypy/pypy/changeset/303ed67a871d/ Log: merge default diff too long, truncating to 2000 out of 3974 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -92,6 +92,8 @@ if sys.platform == "win32": module_suggests["cpyext"].append(("translation.shared", True)) + +# NOTE: this dictionary is not used any more module_import_dependencies = { # no _rawffi if importing rpython.rlib.clibffi raises ImportError # or CompilationError or py.test.skip.Exception @@ -108,6 +110,7 @@ } def get_module_validator(modname): + # NOTE: this function is not used any more if modname in module_import_dependencies: modlist = module_import_dependencies[modname] def validator(config): diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -67,7 +67,7 @@ The other commands of ``setup.py`` are available too, like ``build``. .. _PyPI: https://pypi.python.org/pypi -.. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv +.. _`use virtualenv (as documented here)`: install.html#installing-using-virtualenv Module xyz does not work in the sandboxed PyPy? diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -5,19 +5,8 @@ understanding what's pypy's JIT doing while running your program. There are three functions related to that coming from the ``pypyjit`` module: -.. function:: set_optimize_hook(callable) - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The callable will be called with the ``pypyjit.JitLoopInfo`` object. - Refer to it's documentation for details. - - Result value will be the resulting list of operations, or None - - -.. function:: set_compile_hook(callable) +.. function:: set_compile_hook(callable, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -28,6 +17,9 @@ inside the jit hook is itself jitted, it will get compiled, but the jit hook won't be called for that. + if operations=False, no list of operations will be available. Useful + if the hook is supposed to be very lighweight. + .. function:: set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing @@ -66,3 +58,25 @@ * ``loop_run_times`` - counters for number of times loops are run, only works when ``enable_debug`` is called. + +.. class:: JitLoopInfo + + A class containing information about the compiled loop. Usable attributes: + + * ``operations`` - list of operations, if requested + + * ``jitdriver_name`` - the name of jitdriver associated with this loop + + * ``greenkey`` - a key at which the loop got compiled (e.g. code position, + is_being_profiled, pycode tuple for python jitdriver) + + * ``loop_no`` - loop cardinal number + + * ``bridge_no`` - id of the fail descr + + * ``type`` - "entry bridge", "loop" or "bridge" + + * ``asmaddr`` - an address in raw memory where assembler resides + + * ``asmlen`` - length of raw memory with assembler associated + 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 @@ -21,3 +21,15 @@ .. branch: missing_openssl_include Fix for missing headers in OpenBSD, already applied in downstream ports + +.. branch: gc-more-incremental +Remove a source of non-incremental-ness in the GC: now +external_malloc() no longer runs gc_step_until() any more. If there +is a currently-running major collection, we do only so many steps +before returning. This number of steps depends on the size of the +allocated object. It is controlled by tracking the general progress +of these major collection steps and the size of old objects that +keep adding up between them. + +.. branch: remember-tracing-counts +Reenable jithooks diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - #from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy()#pypy_hooks) + from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -241,20 +241,26 @@ res = libssl_RAND_status() return space.wrap(res) - @unwrap_spec(path=str) - def RAND_egd(space, path): - """RAND_egd(path) -> bytes + if HAVE_OPENSSL_RAND_EGD: + @unwrap_spec(path=str) + def RAND_egd(space, path): + """RAND_egd(path) -> bytes - Queries the entropy gather daemon (EGD) on socket path. Returns number - of bytes read. Raises socket.sslerror if connection to EGD fails or - if it does provide enough data to seed PRNG.""" - with rffi.scoped_str2charp(path) as socket_path: - bytes = libssl_RAND_egd(socket_path) - if bytes == -1: - raise ssl_error(space, - "EGD connection failed or EGD did not return " - "enough data to seed the PRNG") - return space.wrap(bytes) + Queries the entropy gather daemon (EGD) on socket path. Returns number + of bytes read. Raises socket.sslerror if connection to EGD fails or + if it does provide enough data to seed PRNG.""" + with rffi.scoped_str2charp(path) as socket_path: + bytes = libssl_RAND_egd(socket_path) + if bytes == -1: + raise ssl_error(space, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG") + return space.wrap(bytes) + else: + # Dummy func for platforms missing RAND_egd(). Most likely LibreSSL. + @unwrap_spec(path=str) + def RAND_egd(space, path): + raise ssl_error(space, "RAND_egd unavailable") class _SSLSocket(W_Root): diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -36,7 +36,8 @@ assert isinstance(_ssl.OPENSSL_VERSION_INFO, tuple) assert len(_ssl.OPENSSL_VERSION_INFO) == 5 assert isinstance(_ssl.OPENSSL_VERSION, str) - assert 'openssl' in _ssl.OPENSSL_VERSION.lower() + lower_version = _ssl.OPENSSL_VERSION.lower() + assert 'openssl' in lower_version or "libressl" in lower_version assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int) @@ -69,8 +70,9 @@ def test_sslwrap(self): import _ssl, _socket, sys, gc - if sys.platform == 'darwin' or 'freebsd' in sys.platform: - skip("hangs indefinitely on OSX & FreeBSD (also on CPython)") + if sys.platform == 'darwin' or 'freebsd' in sys.platform or \ + 'openbsd' in sys.platform: + skip("hangs indefinitely on OSX & BSD (also on CPython)") s = _socket.socket() if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,6 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype +from rpython.rlib.rarithmetic import ovfcheck from pypy.module.micronumpy import support from pypy.module.micronumpy import constants as NPY @@ -44,9 +45,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(shape) * dtype.elsize + ovfcheck(support.product_check(shape) * dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(shape, dtype.base, order) impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides, zero=zero) @@ -68,9 +69,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - totalsize = support.product(shape) * isize + totalsize = ovfcheck(support.product_check(shape) * isize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if storage_bytes > 0 : if totalsize > storage_bytes: raise OperationError(space.w_TypeError, space.wrap( diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,5 +1,6 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc +from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -409,6 +410,7 @@ make_sure_not_resized(strides) make_sure_not_resized(backstrides) self.shape = shape + # already tested for overflow in from_shape_and_storage self.size = support.product(shape) * dtype.elsize self.order = order self.dtype = dtype @@ -428,9 +430,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(new_shape, self.dtype, self.order) return SliceArray(self.start, strides, backstrides, new_shape, self, @@ -457,8 +459,11 @@ storage=lltype.nullptr(RAW_STORAGE), zero=True): gcstruct = V_OBJECTSTORE flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE - length = support.product(shape) - self.size = length * dtype.elsize + try: + length = support.product_check(shape) + self.size = ovfcheck(length * dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") if storage == lltype.nullptr(RAW_STORAGE): if dtype.num == NPY.OBJECT: storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True) @@ -542,7 +547,10 @@ self.gcstruct = parent.gcstruct self.order = parent.order self.dtype = dtype - self.size = support.product(shape) * self.dtype.elsize + try: + self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED @@ -564,9 +572,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if len(self.get_shape()) < 2 or self.size == 0: # TODO: this code could be refactored into calc_strides # but then calc_strides would have to accept a stepping factor diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -153,7 +153,7 @@ dtype = descriptor.variable_dtype(space, dtype.char + '1') w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) - if support.product(shape) == 1: + if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: loop.assign(space, w_arr, elems_w) @@ -213,10 +213,9 @@ raise OperationError(space.w_ValueError, space.wrap( "negative dimensions are not allowed")) try: - support.product(shape) + support.product_check(shape) except OverflowError: - raise OperationError(space.w_ValueError, space.wrap( - "array is too big.")) + raise oefmt(space.w_ValueError, "array is too big.") return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -6,6 +6,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from rpython.rlib.rawstorage import RAW_STORAGE_PTR +from rpython.rlib.rarithmetic import ovfcheck from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy import descriptor, ufuncs, boxes, arrayops, loop, \ @@ -611,6 +612,7 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + # sz cannot overflow since self is valid sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, @@ -1405,9 +1407,9 @@ return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) try: - totalsize = support.product(shape) * dtype.base.elsize + totalsize = ovfcheck(support.product_check(shape) * dtype.base.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") impl = ConcreteArray(shape, dtype.base, order, strides, backstrides) w_ret = space.allocate_instance(W_NDimArray, w_subtype) W_NDimArray.__init__(w_ret, impl) diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -32,13 +32,19 @@ def product(s): i = 1 for x in s: + i *= x + return i + + at jit.unroll_safe +def product_check(s): + i = 1 + for x in s: try: i = ovfcheck(i * x) except OverflowError: raise return i - def check_and_adjust_index(space, index, size, axis): if index < -size or index >= size: if axis >= 0: diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -270,7 +270,7 @@ exc = raises(ValueError, ndarray, [1,2,256]*10000) assert exc.value[0] == 'sequence too large; must be smaller than 32' exc = raises(ValueError, ndarray, [1,2,256]*10) - assert exc.value[0] == 'array is too big' + assert exc.value[0] == 'array is too big.' def test_ndmin(self): from numpy import array diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -1006,7 +1006,6 @@ assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): # reshape - sz = product(curarg.get_shape()) * curarg.get_dtype().elsize with curarg.implementation as storage: inargs[i] = W_NDimArray.from_shape_and_storage( diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,18 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - #'set_compile_hook': 'interp_resop.set_compile_hook', - #'set_optimize_hook': 'interp_resop.set_optimize_hook', - #'set_abort_hook': 'interp_resop.set_abort_hook', - #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - #'enable_debug': 'interp_resop.enable_debug', - #'disable_debug': 'interp_resop.disable_debug', - #'ResOperation': 'interp_resop.WrappedOp', - #'DebugMergePoint': 'interp_resop.DebugMergePoint', - #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - #'Box': 'interp_resop.WrappedBox', + 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', + 'dont_trace_here': 'interp_jit.dont_trace_here', + 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', + 'set_compile_hook': 'interp_resop.set_compile_hook', + 'set_abort_hook': 'interp_resop.set_abort_hook', + 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + 'enable_debug': 'interp_resop.enable_debug', + 'disable_debug': 'interp_resop.disable_debug', + 'ResOperation': 'interp_resop.WrappedOp', + 'DebugMergePoint': 'interp_resop.DebugMergePoint', + 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -35,10 +35,10 @@ self._compile_hook(debug_info, is_bridge=True) def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) + pass def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) + pass def _compile_hook(self, debug_info, is_bridge): space = self.space @@ -46,7 +46,8 @@ if cache.in_recursion: return if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.compile_hook_with_ops) cache.in_recursion = True try: try: @@ -57,33 +58,4 @@ finally: cache.in_recursion = False - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -5,11 +5,14 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside -from rpython.rlib import jit -from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rlib import jit, jit_hooks +from rpython.rlib.jit import current_trace_length, unroll_parameters,\ + JitHookInterface +from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.pycode import CO_GENERATOR, PyCode +from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame, Yield from pypy.interpreter.baseobjspace import W_Root @@ -188,3 +191,100 @@ __call__ = interp2app(W_NotFromAssembler.descr_call), ) W_NotFromAssembler.typedef.acceptable_as_base_class = False + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + return space.wrap(bool(jit_hooks.get_jitcell_at_key( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode))) + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.dont_trace_here( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.trace_next_iteration( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(hash=r_uint) + at dont_look_inside +def trace_next_iteration_hash(space, hash): + jit_hooks.trace_next_iteration_hash('pypyjit', hash) + return space.w_None + +# class Cache(object): +# in_recursion = False + +# def __init__(self, space): +# self.w_compile_bridge = space.w_None +# self.w_compile_loop = space.w_None + +# def set_compile_bridge(space, w_hook): +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_bridge = w_hook + +# def set_compile_loop(space, w_hook): +# from rpython.rlib.nonconst import NonConstant + +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_loop = w_hook +# cache.in_recursion = NonConstant(False) + +# class PyPyJitHookInterface(JitHookInterface): +# def after_compile(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# l_w = [] +# if not space.is_true(cache.w_compile_loop): +# return +# for i, op in enumerate(debug_info.operations): +# if op.is_guard(): +# w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) +# l_w.append(w_t) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_loop, space.newlist(l_w)) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def after_compile_bridge(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# if not space.is_true(cache.w_compile_bridge): +# return +# w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_bridge, w_hash) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def before_compile(self, debug_info): +# pass + +# def before_compile_bridge(self, debug_info): +# pass + +# pypy_hooks = PyPyJitHookInterface() + diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -22,7 +22,6 @@ def __init__(self, space): self.w_compile_hook = space.w_None self.w_abort_hook = space.w_None - self.w_optimize_hook = space.w_None def getno(self): self.no += 1 @@ -43,8 +42,9 @@ else: return space.wrap(greenkey_repr) -def set_compile_hook(space, w_hook): - """ set_compile_hook(hook) + at unwrap_spec(operations=bool) +def set_compile_hook(space, w_hook, operations=True): + """ set_compile_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -58,25 +58,9 @@ cache = space.fromcache(Cache) assert w_hook is not None cache.w_compile_hook = w_hook + cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) -def set_optimize_hook(space, w_hook): - """ set_optimize_hook(hook) - - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's - docstring for details. - - Result value will be the resulting list of operations, or None - """ - cache = space.fromcache(Cache) - cache.w_optimize_hook = w_hook - cache.in_recursion = NonConstant(False) - - def set_abort_hook(space, w_hook): """ set_abort_hook(hook) @@ -96,6 +80,9 @@ cache.in_recursion = NonConstant(False) def wrap_oplist(space, logops, operations, ops_offset=None): + # this function is called from the JIT + from rpython.jit.metainterp.resoperation import rop + l_w = [] jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd for op in operations: @@ -103,117 +90,58 @@ ofs = -1 else: ofs = ops_offset.get(op, 0) - if op.opnum == rop.DEBUG_MERGE_POINT: + num = op.getopnum() + name = op.getopname() + if num == rop.DEBUG_MERGE_POINT: jd_sd = jitdrivers_sd[op.getarg(0).getint()] greenkey = op.getarglist()[3:] repr = jd_sd.warmstate.get_location_str(greenkey) w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr) - l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op), + l_w.append(DebugMergePoint(space, name, logops.repr_of_resop(op), jd_sd.jitdriver.name, op.getarg(1).getint(), op.getarg(2).getint(), w_greenkey)) else: - l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs, - logops.repr_of_resop(op))) + l_w.append(WrappedOp(name, ofs, logops.repr_of_resop(op))) return l_w + at unwrap_spec(offset=int, repr=str, name=str) +def descr_new_resop(space, w_tp, name, offset=-1, repr=''): + return WrappedOp(name, offset, repr) -class WrappedBox(W_Root): - """ A class representing a single box - """ - def __init__(self, llbox): - self.llbox = llbox - - def descr_getint(self, space): - if not jit_hooks.box_isint(self.llbox): - raise OperationError(space.w_NotImplementedError, - space.wrap("Box has no int value")) - return space.wrap(jit_hooks.box_getint(self.llbox)) - - at unwrap_spec(no=int) -def descr_new_box(space, w_tp, no): - return WrappedBox(jit_hooks.boxint_new(no)) - -WrappedBox.typedef = TypeDef( - 'Box', - __new__ = interp2app(descr_new_box), - getint = interp2app(WrappedBox.descr_getint), -) - - at unwrap_spec(num=int, offset=int, repr=str, w_res=W_Root) -def descr_new_resop(space, w_tp, num, w_args, w_res, offset=-1, - repr=''): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - if space.is_none(w_res): - llres = jit_hooks.emptyval() - else: - if not isinstance(w_res, WrappedBox): - raise OperationError(space.w_TypeError, space.wrap( - "expected box type, got %s" % space.type(w_res))) - llres = w_res.llbox - return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr) - - at unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int) -def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id, + at unwrap_spec(repr=str, name=str, jd_name=str, call_depth=int, call_id=int) +def descr_new_dmp(space, w_tp, name, repr, jd_name, call_depth, call_id, w_greenkey): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - num = rop.DEBUG_MERGE_POINT - return DebugMergePoint(space, - jit_hooks.resop_new(num, args, jit_hooks.emptyval()), + return DebugMergePoint(space, name, repr, jd_name, call_depth, call_id, w_greenkey) class WrappedOp(W_Root): """ A class representing a single ResOperation, wrapped nicely """ - def __init__(self, op, offset, repr_of_resop): - self.op = op + def __init__(self, name, offset, repr_of_resop): self.offset = offset + self.name = name self.repr_of_resop = repr_of_resop def descr_repr(self, space): return space.wrap(self.repr_of_resop) - def descr_num(self, space): - return space.wrap(jit_hooks.resop_getopnum(self.op)) - def descr_name(self, space): - return space.wrap(hlstr(jit_hooks.resop_getopname(self.op))) - - @unwrap_spec(no=int) - def descr_getarg(self, space, no): - try: - box = jit_hooks.resop_getarg(self.op, no) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("Index out of range")) - return WrappedBox(box) - - @unwrap_spec(no=int, w_box=WrappedBox) - def descr_setarg(self, space, no, w_box): - jit_hooks.resop_setarg(self.op, no, w_box.llbox) - - def descr_getresult(self, space): - return WrappedBox(jit_hooks.resop_getresult(self.op)) - - def descr_setresult(self, space, w_box): - box = space.interp_w(WrappedBox, w_box) - jit_hooks.resop_setresult(self.op, box.llbox) + return space.wrap(self.name) class DebugMergePoint(WrappedOp): """ A class representing Debug Merge Point - the entry point to a jitted loop. """ - def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id, - w_greenkey): + def __init__(self, space, name, repr_of_resop, jd_name, call_depth, + call_id, w_greenkey): - WrappedOp.__init__(self, op, -1, repr_of_resop) + WrappedOp.__init__(self, name, -1, repr_of_resop) self.jd_name = jd_name self.call_depth = call_depth self.call_id = call_id @@ -237,12 +165,7 @@ __doc__ = WrappedOp.__doc__, __new__ = interp2app(descr_new_resop), __repr__ = interp2app(WrappedOp.descr_repr), - num = GetSetProperty(WrappedOp.descr_num), name = GetSetProperty(WrappedOp.descr_name), - getarg = interp2app(WrappedOp.descr_getarg), - setarg = interp2app(WrappedOp.descr_setarg), - result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult), offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.typedef.acceptable_as_base_class = False @@ -278,14 +201,18 @@ asmaddr = 0 asmlen = 0 - def __init__(self, space, debug_info, is_bridge=False): - logops = debug_info.logger._make_log_operations() - if debug_info.asminfo is not None: - ofs = debug_info.asminfo.ops_offset + def __init__(self, space, debug_info, is_bridge=False, wrap_ops=True): + if wrap_ops: + memo = {} + logops = debug_info.logger._make_log_operations(memo) + if debug_info.asminfo is not None: + ofs = debug_info.asminfo.ops_offset + else: + ofs = {} + ops = debug_info.operations + self.w_ops = space.newlist(wrap_oplist(space, logops, ops, ofs)) else: - ofs = {} - self.w_ops = space.newlist( - wrap_oplist(space, logops, debug_info.operations, ofs)) + self.w_ops = space.w_None self.jd_name = debug_info.get_jitdriver().name self.type = debug_info.type diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -136,7 +136,6 @@ assert dmp.call_id == 0 assert dmp.offset == -1 assert int_add.name == 'int_add' - assert int_add.num == self.int_add_num assert int_add.offset == 0 self.on_compile_bridge() expected = (') i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) setfield_gc(p167, i119, descr=) - i123 = arraylen_gc(p67, descr=) jump(..., descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -47,7 +47,7 @@ i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) - p34 = new_with_vtable(#) + p34 = new_with_vtable(descr=...) {{{ setfield_gc(p34, p1, descr=) setfield_gc(p34, i25, descr=) @@ -154,7 +154,7 @@ f86 = float_add(f74, f85) i87 = int_add(i76, 1) --TICK-- - jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...) + jump(..., descr=...) """) def test_array_flatiter_next(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -148,6 +148,7 @@ i18 = force_token() setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>) guard_not_invalidated(descr=...) + i84 = int_sub(i14, 1) i21 = int_lt(i10, 0) guard_false(i21, descr=...) i22 = int_lt(i10, i14) @@ -180,6 +181,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i88 = int_sub(i9, 1) i25 = int_ge(i11, i9) guard_false(i25, descr=...) i27 = int_add_ovf(i7, i11) @@ -212,6 +214,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i95 = int_sub(i9, 1) i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -385,7 +385,8 @@ class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeCodePoint)): def union((uchr1, uchr2)): - return SomeUnicodeCodePoint() + no_nul = uchr1.no_nul and uchr2.no_nul + return SomeUnicodeCodePoint(no_nul=no_nul) def add((chr1, chr2)): return SomeUnicodeString() @@ -598,32 +599,33 @@ class __extend__(pairtype(SomeUnicodeString, SomeInteger)): def getitem((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem.can_only_throw = [] def getitem_idx((str1, int2)): - return SomeUnicodeCodePoint() + return SomeUnicodeCodePoint(no_nul=str1.no_nul) getitem_idx.can_only_throw = [IndexError] def mul((str1, int2)): # xxx do we want to support this - return SomeUnicodeString() + return SomeUnicodeString(no_nul=str1.no_nul) class __extend__(pairtype(SomeInteger, SomeString), pairtype(SomeInteger, SomeUnicodeString)): def mul((int1, str2)): # xxx do we want to support this - return str2.basestringclass() + return str2.basestringclass(no_nul=str2.no_nul) class __extend__(pairtype(SomeUnicodeCodePoint, SomeUnicodeString), pairtype(SomeUnicodeString, SomeUnicodeCodePoint), pairtype(SomeUnicodeString, SomeUnicodeString)): def union((str1, str2)): - return SomeUnicodeString(can_be_None=str1.can_be_none() or - str2.can_be_none()) + can_be_None = str1.can_be_None or str2.can_be_None + no_nul = str1.no_nul and str2.no_nul + return SomeUnicodeString(can_be_None=can_be_None, no_nul=no_nul) def add((str1, str2)): # propagate const-ness to help getattr(obj, 'prefix' + const_name) - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=str1.no_nul and str2.no_nul) if str1.is_immutable_constant() and str2.is_immutable_constant(): result.const = str1.const + str2.const return result diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -237,10 +237,11 @@ else: result = SomeString(no_nul=no_nul) elif tp is unicode: + no_nul = not u'\x00' in x if len(x) == 1: - result = SomeUnicodeCodePoint() + result = SomeUnicodeCodePoint(no_nul=no_nul) else: - result = SomeUnicodeString() + result = SomeUnicodeString(no_nul=no_nul) elif tp is bytearray: result = SomeByteArray() elif tp is tuple: diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -438,6 +438,18 @@ assert s.knowntype == str assert s.no_nul + def test_unicode_join(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return [u"foo", u"bar"] + def f(n): + g(0) + return u''.join(g(n)) + s = a.build_types(f, [int]) + assert s.knowntype == unicode + assert s.no_nul + def test_str_split(self): a = self.RPythonAnnotator() def g(n): @@ -451,6 +463,19 @@ s_item = s.listdef.listitem.s_value assert s_item.no_nul + def test_unicode_split(self): + a = self.RPythonAnnotator() + def g(n): + if n: + return u"test string" + def f(n): + if n: + return g(n).split(u' ') + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeList) + s_item = s.listdef.listitem.s_value + assert s_item.no_nul + def test_str_split_nul(self): def f(n): return n.split('\0')[0] @@ -470,6 +495,27 @@ assert not s.can_be_None assert not s.no_nul + def test_unicode_split_nul(self): + def f(n): + return n.split(u'\0')[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert s.no_nul + + def g(n): + return n.split(u'\0', 1)[0] + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(g, [annmodel.SomeUnicodeString( + no_nul=False, can_be_None=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert not s.can_be_None + assert not s.no_nul + def test_str_splitlines(self): a = self.RPythonAnnotator() def f(a_str): @@ -490,6 +536,18 @@ s = a.build_types(f, [int, annmodel.SomeString(no_nul=True)]) assert s.no_nul + def test_unicode_strip(self): + a = self.RPythonAnnotator() + def f(n, a_str): + if n == 0: + return a_str.strip(u' ') + elif n == 1: + return a_str.rstrip(u' ') + else: + return a_str.lstrip(u' ') + s = a.build_types(f, [int, annmodel.SomeUnicodeString(no_nul=True)]) + assert s.no_nul + def test_str_mul(self): a = self.RPythonAnnotator() def f(a_str): @@ -2042,6 +2100,17 @@ assert s.can_be_None assert s.no_nul + def test_unicode_noNUL_canbeNone(self): + def f(a): + if a: + return u"abc" + else: + return None + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_str_or_None(self): def f(a): if a: @@ -2058,6 +2127,22 @@ assert s.can_be_None assert s.no_nul + def test_unicode_or_None(self): + def f(a): + if a: + return u"abc" + else: + return None + def g(a): + x = f(a) + if x is None: + return u"abcd" + return x + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert s.can_be_None + assert s.no_nul + def test_emulated_pbc_call_simple(self): def f(a,b): return a + b @@ -2124,6 +2209,19 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_iteritems_unicode0(self): + def it(d): + return d.iteritems() + def f(): + d0 = {u'1a': u'2a', u'3': u'4'} + for item in it(d0): + return u"%s=%s" % item + raise ValueError + a = self.RPythonAnnotator() + s = a.build_types(f, []) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_no_nul_mod(self): def f(x): s = "%d" % x @@ -2133,6 +2231,14 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + def test_no_nul_mod_unicode(self): + def f(x): + s = u"%d" % x + return s + a = self.RPythonAnnotator() + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_mul_str0(self): def f(s): @@ -2142,6 +2248,24 @@ assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + + def test_reverse_mul_str0(self): + def f(s): + return 10*s + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeString) + assert s.no_nul + + a = self.RPythonAnnotator() + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_getitem_str0(self): def f(s, n): if n == 1: @@ -2153,12 +2277,18 @@ return s a = self.RPythonAnnotator() a.translator.config.translation.check_str_without_nul = True - s = a.build_types(f, [annmodel.SomeString(no_nul=True), annmodel.SomeInteger()]) assert isinstance(s, annmodel.SomeString) assert s.no_nul + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=True), + annmodel.SomeInteger()]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul + def test_non_none_and_none_with_isinstance(self): class A(object): pass @@ -3411,6 +3541,7 @@ a = self.RPythonAnnotator() s = a.build_types(f, [unicode]) assert isinstance(s, annmodel.SomeUnicodeString) + assert s.no_nul def test_unicode_char(self): def f(x, i): @@ -3916,6 +4047,19 @@ assert s.can_be_None assert s.no_nul + def test_contains_no_nul_unicode(self): + def f(i): + if u"\0" in i: + return None + else: + return i + a = self.RPythonAnnotator() + a.translator.config.translation.check_str_without_nul = True + s = a.build_types(f, [annmodel.SomeUnicodeString(no_nul=False)]) + assert isinstance(s, annmodel.SomeUnicodeString) + assert s.can_be_None + assert s.no_nul + def test_no___call__(self): class X(object): def __call__(self): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -574,7 +574,9 @@ return self.basecharclass() def method_split(self, patt, max=-1): - if max == -1 and patt.is_constant() and patt.const == "\0": + # special-case for .split( '\x00') or .split(u'\x00') + if max == -1 and patt.is_constant() and ( + len(patt.const) == 1 and ord(patt.const) == 0): no_nul = True else: no_nul = self.no_nul diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -16,10 +16,11 @@ DEFL_GC = "incminimark" # XXX +DEFL_ROOTFINDER_WITHJIT = "shadowstack" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" -else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + _mach = os.popen('uname -m', 'r').read().strip() + if _mach.startswith('x86') or _mach in ['i386', 'i486', 'i586', 'i686']: + DEFL_ROOTFINDER_WITHJIT = "asmgcc" # only for Linux on x86 / x86-64 IS_64_BITS = sys.maxint > 2147483647 diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -909,7 +909,7 @@ descr.adr_jump_offset = failure_recovery_pos relative_offset = tok.pos_recovery_stub - tok.offset guard_pos = block_start + tok.offset - if not tok.is_guard_not_invalidated: + if not tok.guard_not_invalidated(): # patch the guard jump to the stub # overwrite the generate NOP with a B_offs to the pos of the # stub diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -36,11 +36,9 @@ class ArmGuardToken(GuardToken): def __init__(self, cpu, gcmap, faildescr, failargs, fail_locs, - offset, exc, frame_depth, is_guard_not_invalidated=False, - is_guard_not_forced=False, fcond=c.AL): + offset, guard_opnum, frame_depth, fcond=c.AL): GuardToken.__init__(self, cpu, gcmap, faildescr, failargs, fail_locs, - exc, frame_depth, is_guard_not_invalidated, - is_guard_not_forced) + guard_opnum, frame_depth) self.fcond = fcond self.offset = offset @@ -175,10 +173,7 @@ self.mc.RSB_ri(resloc.value, l0.value, imm=0) return fcond - def build_guard_token(self, op, frame_depth, arglocs, offset, fcond, save_exc, - is_guard_not_invalidated=False, - is_guard_not_forced=False): - assert isinstance(save_exc, bool) + def build_guard_token(self, op, frame_depth, arglocs, offset, fcond): assert isinstance(fcond, int) descr = op.getdescr() assert isinstance(descr, AbstractFailDescr) @@ -189,16 +184,12 @@ failargs=op.getfailargs(), fail_locs=arglocs, offset=offset, - exc=save_exc, + guard_opnum=op.getopnum(), frame_depth=frame_depth, - is_guard_not_invalidated=is_guard_not_invalidated, - is_guard_not_forced=is_guard_not_forced, fcond=fcond) return token - def _emit_guard(self, op, arglocs, save_exc, - is_guard_not_invalidated=False, - is_guard_not_forced=False): + def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False): if is_guard_not_invalidated: fcond = c.cond_none else: @@ -206,10 +197,9 @@ self.guard_success_cc = c.cond_none assert fcond != c.cond_none pos = self.mc.currpos() - token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond, save_exc, - is_guard_not_invalidated, - is_guard_not_forced) + token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond) self.pending_guards.append(token) + assert token.guard_not_invalidated() == is_guard_not_invalidated # For all guards that are not GUARD_NOT_INVALIDATED we emit a # breakpoint to ensure the location is patched correctly. In the case # of GUARD_NOT_INVALIDATED we use just a NOP, because it is only @@ -221,12 +211,12 @@ return c.AL def emit_op_guard_true(self, op, arglocs, regalloc, fcond): - fcond = self._emit_guard(op, arglocs, save_exc=False) + fcond = self._emit_guard(op, arglocs) return fcond def emit_op_guard_false(self, op, arglocs, regalloc, fcond): self.guard_success_cc = c.get_opposite_of(self.guard_success_cc) - fcond = self._emit_guard(op, arglocs, save_exc=False) + fcond = self._emit_guard(op, arglocs) return fcond def emit_op_guard_value(self, op, arglocs, regalloc, fcond): @@ -244,7 +234,7 @@ self.mc.VCMP(l0.value, l1.value) self.mc.VMRS(cond=fcond) self.guard_success_cc = c.EQ - fcond = self._emit_guard(op, failargs, save_exc=False) + fcond = self._emit_guard(op, failargs) return fcond emit_op_guard_nonnull = emit_op_guard_true @@ -256,14 +246,14 @@ def emit_op_guard_class(self, op, arglocs, regalloc, fcond): self._cmp_guard_class(op, arglocs, regalloc, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_nonnull_class(self, op, arglocs, regalloc, fcond): self.mc.CMP_ri(arglocs[0].value, 1) self._cmp_guard_class(op, arglocs, regalloc, c.HS) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def _cmp_guard_class(self, op, locs, regalloc, fcond): @@ -288,7 +278,7 @@ def emit_op_guard_gc_type(self, op, arglocs, regalloc, fcond): self._cmp_guard_gc_type(arglocs[0], arglocs[1].value, fcond) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_is_object(self, op, arglocs, regalloc, fcond): @@ -309,7 +299,7 @@ self.mc.LDRB_rr(r.ip.value, r.ip.value, r.lr.value) self.mc.TST_ri(r.ip.value, imm=(IS_OBJECT_FLAG & 0xff)) self.guard_success_cc = c.NE - self._emit_guard(op, arglocs[1:], save_exc=False) + self._emit_guard(op, arglocs[1:]) return fcond def emit_op_guard_subclass(self, op, arglocs, regalloc, fcond): @@ -353,12 +343,11 @@ self.mc.CMP_rr(r.ip.value, r.lr.value) # the guard passes if we get a result of "below or equal" self.guard_success_cc = c.LS - self._emit_guard(op, arglocs[2:], save_exc=False) + self._emit_guard(op, arglocs[2:]) return fcond def emit_op_guard_not_invalidated(self, op, locs, regalloc, fcond): - return self._emit_guard(op, locs, save_exc=False, - is_guard_not_invalidated=True) + return self._emit_guard(op, locs, is_guard_not_invalidated=True) def emit_op_label(self, op, arglocs, regalloc, fcond): self._check_frame_depth_debug(self.mc) @@ -498,7 +487,7 @@ self.mc.LDR_ri(loc.value, loc.value) self.mc.CMP_ri(loc.value, 0) self.guard_success_cc = c.EQ - fcond = self._emit_guard(op, failargs, save_exc=True) + fcond = self._emit_guard(op, failargs) # If the previous operation was a COND_CALL, overwrite its conditional # jump to jump over this GUARD_NO_EXCEPTION as well, if we can if self._find_nearby_operation(-1).getopnum() == rop.COND_CALL: @@ -515,7 +504,7 @@ self.mc.CMP_rr(r.ip.value, loc.value) self.guard_success_cc = c.EQ - self._emit_guard(op, failargs, save_exc=True) + self._emit_guard(op, failargs) self._store_and_reset_exception(self.mc, resloc) return fcond @@ -1047,7 +1036,7 @@ def store_force_descr(self, op, fail_locs, frame_depth): pos = self.mc.currpos() - guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, c.AL, True, False, True) + guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, c.AL) #self.pending_guards.append(guard_token) self._finish_gcmap = guard_token.gcmap self._store_force_index(op) @@ -1152,7 +1141,7 @@ self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) self.guard_success_cc = c.EQ - self._emit_guard(op, arglocs, save_exc=True, is_guard_not_forced=True) + self._emit_guard(op, arglocs) return fcond def _genop_call_may_force(self, op, arglocs, regalloc, fcond): diff --git a/rpython/jit/backend/arm/test/support.py b/rpython/jit/backend/arm/test/support.py --- a/rpython/jit/backend/arm/test/support.py +++ b/rpython/jit/backend/arm/test/support.py @@ -10,7 +10,9 @@ class JitARMMixin(support.LLJitMixin): type_system = 'lltype' CPUClass = getcpuclass() - basic = True + # we have to disable unroll + enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap" + basic = False def check_jumps(self, maxcount): pass diff --git a/rpython/jit/backend/arm/test/test_calling_convention.py b/rpython/jit/backend/arm/test/test_calling_convention.py --- a/rpython/jit/backend/arm/test/test_calling_convention.py +++ b/rpython/jit/backend/arm/test/test_calling_convention.py @@ -10,18 +10,14 @@ from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.test.support import skip_unless_run_slow_tests from rpython.jit.backend.arm.test.test_runner import boxfloat, constfloat -from rpython.jit.metainterp.resoperation import ResOperation, rop -from rpython.jit.metainterp.history import (AbstractFailDescr, - AbstractDescr, - BasicFailDescr, - BasicFinalDescr, - BoxInt, Box, BoxPtr, - JitCellToken, TargetToken, - ConstInt, ConstPtr, - BoxFloat, ConstFloat) +from rpython.jit.metainterp.resoperation import rop, InputArgInt, InputArgFloat +from rpython.jit.metainterp.history import JitCellToken skip_unless_run_slow_tests() +boxint = InputArgInt +boxfloat = InputArgFloat.fromfloat + class TestARMCallingConvention(CallingConvTests): # ../../test/calling_convention_test.py @@ -82,9 +78,9 @@ EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([boxfloat(.1) for i in range(7)] + - [BoxInt(1), boxfloat(.2), BoxInt(2), boxfloat(.3), + [boxint(1), boxfloat(.2), boxint(2), boxfloat(.3), boxfloat(.4)]) - res = self.execute_operation(rop.CALL, + res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) for i,j in enumerate(callargs[0]): @@ -112,7 +108,7 @@ EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) args = ([boxfloat(.1) for i in range(10)]) - res = self.execute_operation(rop.CALL, + res = self.execute_operation(rop.CALL_F, [funcbox] + args, 'float', descr=calldescr) for i,j in enumerate(callargs[0]): @@ -134,8 +130,8 @@ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) - args = ([BoxInt(1) for i in range(10)]) - res = self.execute_operation(rop.CALL, + args = ([boxint(1) for i in range(10)]) + res = self.execute_operation(rop.CALL_I, [funcbox] + args, 'int', descr=calldescr) for i,j in enumerate(callargs[0]): diff --git a/rpython/jit/backend/arm/test/test_generated.py b/rpython/jit/backend/arm/test/test_generated.py --- a/rpython/jit/backend/arm/test/test_generated.py +++ b/rpython/jit/backend/arm/test/test_generated.py @@ -1,4 +1,6 @@ import py +py.test.skip("XXX FIX ME OR KILL ME") + from rpython.jit.metainterp.history import (AbstractFailDescr, AbstractDescr, BasicFailDescr, diff --git a/rpython/jit/backend/arm/test/test_helper.py b/rpython/jit/backend/arm/test/test_helper.py --- a/rpython/jit/backend/arm/test/test_helper.py +++ b/rpython/jit/backend/arm/test/test_helper.py @@ -1,6 +1,8 @@ from rpython.jit.backend.arm.helper.assembler import count_reg_args -from rpython.jit.metainterp.history import (BoxInt, BoxPtr, BoxFloat, - INT, REF, FLOAT) +from rpython.jit.metainterp.history import INT, REF, FLOAT +from rpython.jit.metainterp.resoperation import InputArgInt as BoxInt +from rpython.jit.metainterp.resoperation import InputArgRef as BoxPtr +from rpython.jit.metainterp.resoperation import InputArgFloat as BoxFloat def test_count_reg_args(): diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py --- a/rpython/jit/backend/arm/test/test_regalloc.py +++ b/rpython/jit/backend/arm/test/test_regalloc.py @@ -215,14 +215,14 @@ def test_exception_bridge_no_exception(self): ops = ''' [i0] - i1 = same_as(1) - call(ConstClass(raising_fptr), i0, descr=raising_calldescr) + i1 = same_as_i(1) + call_n(ConstClass(raising_fptr), i0, descr=raising_calldescr) guard_exception(ConstClass(zero_division_error)) [i1] finish(0) ''' bridge_ops = ''' [i3] - i2 = same_as(2) + i2 = same_as_i(2) guard_no_exception() [i2] finish(1) ''' @@ -379,7 +379,7 @@ def test_bug_wrong_stack_adj(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8] - i9 = same_as(0) + i9 = same_as_i(0) guard_true(i0) [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -387,7 +387,7 @@ assert self.getint(0) == 0 bridge_ops = ''' [i9, i0, i1, i2, i3, i4, i5, i6, i7, i8] - call(ConstClass(raising_fptr), 0, descr=raising_calldescr) + call_n(ConstClass(raising_fptr), 0, descr=raising_calldescr) guard_true(i0) [i0, i1, i2, i3, i4, i5, i6, i7, i8] finish(1) ''' @@ -430,7 +430,7 @@ def test_cmp_op_0(self): ops = ''' [i0, i3] - i1 = same_as(1) + i1 = same_as_i(1) i2 = int_lt(i0, 100) guard_true(i3) [i1, i2] finish(i2) @@ -630,7 +630,7 @@ def test_one_call(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_true(i10), [i10, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -639,8 +639,8 @@ def test_two_calls(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9] - i10 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) - i11 = call(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) + i10 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) + i11 = call_i(ConstClass(f2ptr), i10, i1, descr=f2_calldescr) guard_true(i11) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9] ''' self.interpret(ops, [4, 7, 9, 9, 9, 9, 9, 9, 9, 9]) @@ -649,7 +649,7 @@ def test_call_many_arguments(self): ops = ''' [i0, i1, i2, i3, i4, i5, i6, i7] - i8 = call(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) + i8 = call_i(ConstClass(f10ptr), 1, i0, i1, i2, i3, i4, i5, i6, i7, 10, descr=f10_calldescr) finish(i8) ''' self.interpret(ops, [2, 3, 4, 5, 6, 7, 8, 9]) @@ -658,7 +658,7 @@ def test_bridge_calls_1(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f1ptr), i0, descr=f1_calldescr) + i2 = call_i(ConstClass(f1ptr), i0, descr=f1_calldescr) guard_value(i2, 0, descr=fdescr1) [i2, i1] finish(i1) ''' @@ -666,7 +666,7 @@ assert self.getint(0) == 5 ops = ''' [i2, i1] - i3 = call(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) + i3 = call_i(ConstClass(f2ptr), i2, i1, descr=f2_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -677,7 +677,7 @@ def test_bridge_calls_2(self): ops = ''' [i0, i1] - i2 = call(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) + i2 = call_i(ConstClass(f2ptr), i0, i1, descr=f2_calldescr) guard_value(i2, 0, descr=fdescr1) [i2] finish(i1) ''' @@ -685,7 +685,7 @@ assert self.getint(0) == 4 * 7 ops = ''' [i2] - i3 = call(ConstClass(f1ptr), i2, descr=f1_calldescr) + i3 = call_i(ConstClass(f1ptr), i2, descr=f1_calldescr) finish(i3) ''' self.attach_bridge(ops, loop, -2) @@ -734,7 +734,7 @@ loop2 = """ [i0] i1 = force_token() - i2 = call_assembler(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) + i2 = call_assembler_i(1,2,3,4,5,6,7,8,9,10,11, descr=looptoken) guard_not_forced() [i0] guard_false(i0) [i0, i2] """ @@ -749,23 +749,23 @@ label(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) i11 = int_add(i0, 1) i12 = int_lt(i11, 2) - i13 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i14 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i15 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i16 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i17 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i18 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i19 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i20 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i21 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i22 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i23 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i24 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i26 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i27 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i28 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i29 = call(ConstClass(f_fptr), i12, descr=f_calldescr) - i30 = call(ConstClass(f_fptr), i12, descr=f_calldescr) + i13 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i14 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i15 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i16 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i17 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i18 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i19 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i20 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i21 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i22 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i23 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i24 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i26 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i27 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i28 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i29 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) + i30 = call_i(ConstClass(f_fptr), i12, descr=f_calldescr) guard_true(i12) [i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10] jump(i11, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, descr=targettoken) """ diff --git a/rpython/jit/backend/arm/test/test_regalloc2.py b/rpython/jit/backend/arm/test/test_regalloc2.py deleted file mode 100644 --- a/rpython/jit/backend/arm/test/test_regalloc2.py +++ /dev/null @@ -1,281 +0,0 @@ -import py -from rpython.jit.metainterp.history import ResOperation, BoxInt, ConstInt,\ - BoxPtr, ConstPtr, BasicFailDescr, BasicFinalDescr -from rpython.jit.metainterp.history import JitCellToken -from rpython.jit.metainterp.resoperation import rop -from rpython.jit.backend.detect_cpu import getcpuclass -from rpython.jit.backend.arm.arch import WORD -CPU = getcpuclass() - -def test_bug_rshift(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_ADD, [v1, v1], v2), - ResOperation(rop.INT_INVERT, [v2], v3), - ResOperation(rop.UINT_RSHIFT, [v1, ConstInt(3)], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(1)), - ] - operations[-2].setfailargs([v4, v3]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, 9) - assert cpu.get_int_value(deadframe, 0) == (9 >> 3) - assert cpu.get_int_value(deadframe, 1) == (~18) - -def test_bug_int_is_true_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - tmp5 = BoxInt() - inputargs = [v1] - operations = [ - ResOperation(rop.INT_MUL, [v1, v1], v2), - ResOperation(rop.INT_MUL, [v2, v1], v3), - ResOperation(rop.INT_IS_TRUE, [v2], tmp5), - ResOperation(rop.INT_IS_ZERO, [tmp5], v4), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr()), - ] - operations[-2].setfailargs([v4, v3, tmp5]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - deadframe = cpu.execute_token(looptoken, -10) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == -1000 - assert cpu.get_int_value(deadframe, 2) == 1 - -def test_bug_0(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - tmp46 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_GT, [v3, ConstInt(-48)], v11), - ResOperation(rop.INT_XOR, [v8, v1], v12), - ResOperation(rop.INT_GT, [v6, ConstInt(-9)], v13), - ResOperation(rop.INT_LE, [v13, v2], v14), - ResOperation(rop.INT_LE, [v11, v5], v15), - ResOperation(rop.UINT_GE, [v13, v13], v16), - ResOperation(rop.INT_OR, [v9, ConstInt(-23)], v17), - ResOperation(rop.INT_LT, [v10, v13], v18), - ResOperation(rop.INT_OR, [v15, v5], v19), - ResOperation(rop.INT_XOR, [v17, ConstInt(54)], v20), - ResOperation(rop.INT_MUL, [v8, v10], v21), - ResOperation(rop.INT_OR, [v3, v9], v22), - ResOperation(rop.INT_AND, [v11, ConstInt(-4)], tmp41), - ResOperation(rop.INT_OR, [tmp41, ConstInt(1)], tmp42), - ResOperation(rop.INT_MOD, [v12, tmp42], v23), - ResOperation(rop.INT_IS_TRUE, [v6], v24), - ResOperation(rop.UINT_RSHIFT, [v15, ConstInt(6)], v25), - ResOperation(rop.INT_OR, [ConstInt(-4), v25], v26), - ResOperation(rop.INT_INVERT, [v8], v27), - ResOperation(rop.INT_SUB, [ConstInt(-113), v11], v28), - ResOperation(rop.INT_NEG, [v7], v29), - ResOperation(rop.INT_NEG, [v24], v30), - ResOperation(rop.INT_FLOORDIV, [v3, ConstInt(53)], v31), - ResOperation(rop.INT_MUL, [v28, v27], v32), - ResOperation(rop.INT_AND, [v18, ConstInt(-4)], tmp43), - ResOperation(rop.INT_OR, [tmp43, ConstInt(1)], tmp44), - ResOperation(rop.INT_MOD, [v26, tmp44], v33), - ResOperation(rop.INT_OR, [v27, v19], v34), - ResOperation(rop.UINT_LT, [v13, ConstInt(1)], v35), - ResOperation(rop.INT_AND, [v21, ConstInt(31)], tmp45), - ResOperation(rop.INT_RSHIFT, [v21, tmp45], v36), - ResOperation(rop.INT_AND, [v20, ConstInt(31)], tmp46), - ResOperation(rop.UINT_RSHIFT, [v4, tmp46], v37), - ResOperation(rop.UINT_GT, [v33, ConstInt(-11)], v38), - ResOperation(rop.INT_NEG, [v7], v39), - ResOperation(rop.INT_GT, [v24, v32], v40), - ResOperation(rop.GUARD_FALSE, [v1], None, descr=BasicFailDescr()), - ] - operations[-1].setfailargs([v40, v36, v37, v31, v16, v34, v35, v23, v22, v29, v14, v39, v30, v38]) - cpu = CPU(None, None) - cpu.setup_once() - looptoken = JitCellToken() - cpu.compile_loop(inputargs, operations, looptoken) - args = [-13 , 10 , 10 , 8 , -8 , -16 , -18 , 46 , -12 , 26] - deadframe = cpu.execute_token(looptoken, *args) - assert cpu.get_int_value(deadframe, 0) == 0 - assert cpu.get_int_value(deadframe, 1) == 0 - assert cpu.get_int_value(deadframe, 2) == 0 - assert cpu.get_int_value(deadframe, 3) == 0 - assert cpu.get_int_value(deadframe, 4) == 1 - assert cpu.get_int_value(deadframe, 5) == -7 - assert cpu.get_int_value(deadframe, 6) == 1 - assert cpu.get_int_value(deadframe, 7) == 0 - assert cpu.get_int_value(deadframe, 8) == -2 - assert cpu.get_int_value(deadframe, 9) == 18 - assert cpu.get_int_value(deadframe, 10) == 1 - assert cpu.get_int_value(deadframe, 11) == 18 - assert cpu.get_int_value(deadframe, 12) == -1 - assert cpu.get_int_value(deadframe, 13) == 0 - -def test_bug_1(): - v1 = BoxInt() - v2 = BoxInt() - v3 = BoxInt() - v4 = BoxInt() - v5 = BoxInt() - v6 = BoxInt() - v7 = BoxInt() - v8 = BoxInt() - v9 = BoxInt() - v10 = BoxInt() - v11 = BoxInt() - v12 = BoxInt() - v13 = BoxInt() - v14 = BoxInt() - v15 = BoxInt() - v16 = BoxInt() - v17 = BoxInt() - v18 = BoxInt() - v19 = BoxInt() - v20 = BoxInt() - v21 = BoxInt() - v22 = BoxInt() - v23 = BoxInt() - v24 = BoxInt() - v25 = BoxInt() - v26 = BoxInt() - v27 = BoxInt() - v28 = BoxInt() - v29 = BoxInt() - v30 = BoxInt() - v31 = BoxInt() - v32 = BoxInt() - v33 = BoxInt() - v34 = BoxInt() - v35 = BoxInt() - v36 = BoxInt() - v37 = BoxInt() - v38 = BoxInt() - v39 = BoxInt() - v40 = BoxInt() - tmp41 = BoxInt() - tmp42 = BoxInt() - tmp43 = BoxInt() - tmp44 = BoxInt() - tmp45 = BoxInt() - inputargs = [v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] - operations = [ - ResOperation(rop.UINT_LT, [v6, ConstInt(0)], v11), - ResOperation(rop.INT_AND, [v3, ConstInt(31)], tmp41), - ResOperation(rop.INT_RSHIFT, [v3, tmp41], v12), - ResOperation(rop.INT_NEG, [v2], v13), - ResOperation(rop.INT_ADD, [v11, v7], v14), - ResOperation(rop.INT_OR, [v3, v2], v15), - ResOperation(rop.INT_OR, [v12, v12], v16), - ResOperation(rop.INT_NE, [v2, v5], v17), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp42), - ResOperation(rop.UINT_RSHIFT, [v14, tmp42], v18), - ResOperation(rop.INT_AND, [v14, ConstInt(31)], tmp43), - ResOperation(rop.INT_LSHIFT, [ConstInt(7), tmp43], v19), - ResOperation(rop.INT_NEG, [v19], v20), - ResOperation(rop.INT_MOD, [v3, ConstInt(1)], v21), - ResOperation(rop.UINT_GE, [v15, v1], v22), - ResOperation(rop.INT_AND, [v16, ConstInt(31)], tmp44), - ResOperation(rop.INT_LSHIFT, [v8, tmp44], v23), - ResOperation(rop.INT_IS_TRUE, [v17], v24), - ResOperation(rop.INT_AND, [v5, ConstInt(31)], tmp45), - ResOperation(rop.INT_LSHIFT, [v14, tmp45], v25), - ResOperation(rop.INT_LSHIFT, [v5, ConstInt(17)], v26), - ResOperation(rop.INT_EQ, [v9, v15], v27), From noreply at buildbot.pypy.org Sun Sep 27 18:48:12 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 18:48:12 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: be a bit more precise about the resume position Message-ID: <20150927164812.60B5A1C089E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79868:f0e67a65063e Date: 2015-09-27 18:48 +0200 http://bitbucket.org/pypy/pypy/changeset/f0e67a65063e/ Log: be a bit more precise about the resume position 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 @@ -21,6 +21,7 @@ from rpython.rlib.unroll import unrolling_iterable from rpython.rtyper.lltypesystem import lltype, rffi, llmemory from rpython.rtyper import rclass +from rpython.rlib.objectmodel import compute_unique_id @@ -2475,7 +2476,7 @@ if isinstance(resumedescr, compile.ResumeGuardDescr): name = resumedescr.rd_frame_info_list.jitcode.name pc = resumedescr.rd_frame_info_list.pc - debug_print("resuming at %s %d" % (name, pc)) + debug_print("resuming at %d %s %d" % (name, pc, compute_unique_id(resumedescr))) if isinstance(resumedescr, compile.ResumeGuardExcDescr): if exception: self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, From noreply at buildbot.pypy.org Sun Sep 27 18:48:33 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 18:48:33 +0200 (CEST) Subject: [pypy-commit] pypy default: Trying half-heartedly to fix the timeout error that shows up every night Message-ID: <20150927164833.C0CD21C089E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79869:598733b07629 Date: 2015-09-27 18:49 +0200 http://bitbucket.org/pypy/pypy/changeset/598733b07629/ Log: Trying half-heartedly to fix the timeout error that shows up every night (with, of course, no clue about where it is) diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -123,23 +123,26 @@ self.sig_recvd = True old_handler = signal.signal(signal.SIGUSR1, my_handler) try: + ready = thread.allocate_lock() + ready.acquire() def other_thread(): # Acquire the lock in a non-main thread, so this test works for # RLocks. lock.acquire() - # Wait until the main thread is blocked in the lock acquire, and - # then wake it up with this. - time.sleep(0.5) + # Notify the main thread that we're ready + ready.release() + # Wait for 5 seconds here + for n in range(50): + time.sleep(0.1) + # Send the signal os.kill(os.getpid(), signal.SIGUSR1) # Let the main thread take the interrupt, handle it, and retry # the lock acquisition. Then we'll let it run. - time.sleep(0.5) + for n in range(50): + time.sleep(0.1) lock.release() thread.start_new_thread(other_thread, ()) - # Wait until we can't acquire it without blocking... - while lock.acquire(blocking=False): - lock.release() - time.sleep(0.01) + ready.acquire() result = lock.acquire() # Block while we receive a signal. assert self.sig_recvd assert result From noreply at buildbot.pypy.org Sun Sep 27 19:07:32 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 19:07:32 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: disable this optimization Message-ID: <20150927170732.999321C13F7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79870:651d73ba0f96 Date: 2015-09-27 19:07 +0200 http://bitbucket.org/pypy/pypy/changeset/651d73ba0f96/ Log: disable this optimization 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 @@ -502,7 +502,7 @@ origin_jitcode=None, origin_pc=0): if origin_jitcode is not None: debug_print("looking for guard at %s %d" % (origin_jitcode.name, origin_pc)) - self.origin_jitcode = origin_jitcode + self.origin_jitcode = None # origin_jitcode self.origin_pc = origin_pc if rename_inputargs: newargs = [] From noreply at buildbot.pypy.org Sun Sep 27 20:01:13 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 20:01:13 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: merge default Message-ID: <20150927180113.967E91C1F7F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79871:be6fe02ea18a Date: 2015-09-27 20:01 +0200 http://bitbucket.org/pypy/pypy/changeset/be6fe02ea18a/ Log: merge default diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -5,8 +5,8 @@ with any external library. Right now, there are the following possibilities of providing -third-party modules for the PyPy python interpreter (in order of -usefulness): +third-party modules for the PyPy python interpreter (in order, from most +directly useful to most messy to use with PyPy): * Write them in pure Python and use CFFI_. 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 @@ -33,3 +33,13 @@ .. branch: remember-tracing-counts Reenable jithooks + +.. branch: detect_egd2 + +.. branch: shadowstack-no-move-2 +Issue #2141: fix a crash on Windows and OS/X and ARM when running +at least 20 threads. + +.. branch: numpy-ctypes + +Add support for ndarray.ctypes property. diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -125,12 +125,24 @@ cdata[0] = value +# XXX explicitly use an integer type instead of lltype.UniChar here, +# because for now the latter is defined as unsigned by RPython (even +# though it may be signed when 'wchar_t' is written to C). +WCHAR_INT = {(2, False): rffi.USHORT, + (4, False): rffi.UINT, + (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar), rffi.r_wchar_t.SIGN] +WCHAR_INTP = rffi.CArrayPtr(WCHAR_INT) + class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar): _attrs_ = [] + if rffi.r_wchar_t.SIGN: + def write_raw_integer_data(self, w_cdata, value): + w_cdata.write_raw_signed_data(value) + def cast_to_int(self, cdata): - unichardata = rffi.cast(rffi.CWCHARP, cdata) - return self.space.wrap(ord(unichardata[0])) + unichardata = rffi.cast(WCHAR_INTP, cdata) + return self.space.wrap(unichardata[0]) def convert_to_object(self, cdata): unichardata = rffi.cast(rffi.CWCHARP, cdata) diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -34,6 +34,7 @@ i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) i += 2 * WORD + size * struct.calcsize("P") + i += WORD # thread id elif s[i] == '\x02': i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -9,6 +9,7 @@ 'ndarray': 'ndarray.W_NDimArray', 'dtype': 'descriptor.W_Dtype', 'flatiter': 'flatiter.W_FlatIterator', + 'flagsobj': 'flagsobj.W_FlagsObject', '_reconstruct' : 'ndarray._reconstruct', 'scalar' : 'ctors.build_scalar', diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -147,7 +147,7 @@ def get_flags(self): return (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS | - NPY.ARRAY_WRITEABLE | NPY.ARRAY_OWNDATA) + NPY.ARRAY_ALIGNED | NPY.ARRAY_OWNDATA) def item(self, space): return self.get_dtype(space).itemtype.to_builtin_type(space, self) diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -17,6 +18,19 @@ is_f_contiguous) from rpython.rlib.objectmodel import keepalive_until_here +TimSort = make_timsort_class() +class StrideSort(TimSort): + ''' + argsort (return the indices to sort) a list of strides + ''' + def __init__(self, rangelist, strides): + self.strides = strides + TimSort.__init__(self, rangelist) + + def lt(self, a, b): + return self.strides[a] < self.strides[b] + + class BaseConcreteArray(object): _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]', 'strides[*]', 'backstrides[*]', 'order', 'gcstruct', @@ -354,12 +368,15 @@ elif order != self.order: t_strides, backstrides = calc_strides(shape, dtype, order) else: - mins = strides[0] + indx_array = range(len(strides)) + list_sorter = StrideSort(indx_array, strides) + list_sorter.sort() t_elsize = dtype.elsize - for s in strides: - if s < mins: - mins = s - t_strides = [s * t_elsize / mins for s in strides] + t_strides = strides[:] + base = dtype.elsize + for i in indx_array: + t_strides[i] = base + base *= shape[i] backstrides = calc_backstrides(t_strides, shape) impl = ConcreteArray(shape, dtype, order, t_strides, backstrides) loop.setslice(space, impl.get_shape(), impl, self) @@ -551,6 +568,11 @@ self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) except OverflowError: raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") + while orig_arr is not None: + assert isinstance(orig_arr, W_NDimArray) + if orig_arr.implementation.base() is None: + break + orig_arr = orig_arr.implementation.base() self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py --- a/pypy/module/micronumpy/flagsobj.py +++ b/pypy/module/micronumpy/flagsobj.py @@ -57,6 +57,9 @@ self.flags & NPY.ARRAY_F_CONTIGUOUS or self.flags & NPY.ARRAY_C_CONTIGUOUS )) + def descr_get_num(self, space): + return space.wrap(self.flags) + def descr_getitem(self, space, w_item): key = space.str_w(w_item) if key == "C" or key == "CONTIGUOUS" or key == "C_CONTIGUOUS": @@ -122,4 +125,5 @@ aligned = GetSetProperty(W_FlagsObject.descr_get_aligned), fnc = GetSetProperty(W_FlagsObject.descr_get_fnc), forc = GetSetProperty(W_FlagsObject.descr_get_forc), + num = GetSetProperty(W_FlagsObject.descr_get_num), ) diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -747,8 +747,12 @@ return out def descr_get_ctypes(self, space): - raise OperationError(space.w_NotImplementedError, space.wrap( - "ctypes not implemented yet")) + w_result = space.appexec([self], """(arr): + from numpy.core import _internal + p_data = arr.__array_interface__['data'][0] + return _internal._ctypes(arr, p_data) + """) + return w_result def buffer_w(self, space, flags): return self.implementation.get_buffer(space, True) diff --git a/pypy/module/micronumpy/test/test_flagsobj.py b/pypy/module/micronumpy/test/test_flagsobj.py --- a/pypy/module/micronumpy/test/test_flagsobj.py +++ b/pypy/module/micronumpy/test/test_flagsobj.py @@ -30,6 +30,7 @@ assert a.flags.forc == True assert a.flags['FNC'] == False assert a.flags['FORC'] == True + assert a.flags.num == 1287 raises(KeyError, "a.flags['blah']") raises(KeyError, "a.flags['C_CONTIGUOUS'] = False") raises((TypeError, AttributeError), "a.flags.c_contiguous = False") @@ -38,6 +39,7 @@ import numpy as np a = np.int32(2) assert a.flags.c_contiguous == True + assert a.flags.num == 263 def test_compare(self): import numpy as np diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -2218,7 +2218,7 @@ assert _weakref.ref(a) def test_astype(self): - from numpy import array, arange + from numpy import array, arange, empty b = array(1).astype(float) assert b == 1 assert b.dtype == float @@ -2273,14 +2273,36 @@ b = a.astype('f4', order='C', copy=False) assert a is b + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + c = b[:, :2, :] + d = c.swapaxes(1, -1) + e = d.astype('complex128') + assert e.shape == (3, 3, 2) + assert e.strides == (96, 16, 48) + assert (e.real == d).all() + def test_base(self): - from numpy import array + from numpy import array, empty assert array(1).base is None assert array([1, 2]).base is None a = array([1, 2, 3, 4]) b = a[::2] assert b.base is a + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + assert b.base.base is None + c = b[:, :2, :] + d = c.swapaxes(1, -1) + assert c.base.base is None + assert d.base.base is None + assert d.shape == (3, 3, 2) + assert d.__array_interface__['data'][0] == \ + a.__array_interface__['data'][0] + a.strides[0] * 2 + def test_byteswap(self): from numpy import array diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -123,23 +123,26 @@ self.sig_recvd = True old_handler = signal.signal(signal.SIGUSR1, my_handler) try: + ready = thread.allocate_lock() + ready.acquire() def other_thread(): # Acquire the lock in a non-main thread, so this test works for # RLocks. lock.acquire() - # Wait until the main thread is blocked in the lock acquire, and - # then wake it up with this. - time.sleep(0.5) + # Notify the main thread that we're ready + ready.release() + # Wait for 5 seconds here + for n in range(50): + time.sleep(0.1) + # Send the signal os.kill(os.getpid(), signal.SIGUSR1) # Let the main thread take the interrupt, handle it, and retry # the lock acquisition. Then we'll let it run. - time.sleep(0.5) + for n in range(50): + time.sleep(0.1) lock.release() thread.start_new_thread(other_thread, ()) - # Wait until we can't acquire it without blocking... - while lock.acquire(blocking=False): - lock.release() - time.sleep(0.01) + ready.acquire() result = lock.acquire() # Block while we receive a signal. assert self.sig_recvd assert result diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -4,6 +4,7 @@ from rpython.rlib import rarithmetic, rfloat from rpython.rlib.rarithmetic import LONG_BIT, intmask, ovfcheck_float_to_int +from rpython.rlib.rarithmetic import int_between from rpython.rlib.rbigint import rbigint from rpython.rlib.rfloat import ( DTSF_ADD_DOT_0, DTSF_STR_PRECISION, INFINITY, NAN, copysign, @@ -121,10 +122,11 @@ if space.isinstance_w(w_other, space.w_int): f1 = self.floatval i2 = space.int_w(w_other) - f2 = float(i2) - if LONG_BIT > 32 and int(f2) != i2: + # (double-)floats have always at least 48 bits of precision + if LONG_BIT > 32 and not int_between((-1)<<48, i2, 1<<48): res = do_compare_bigint(f1, rbigint.fromint(i2)) else: + f2 = float(i2) res = op(f1, f2) return space.newbool(res) if space.isinstance_w(w_other, space.w_long): diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -840,3 +840,12 @@ check(mod(0.0, -1.0), -0.0) check(mod(1e-100, -1.0), -1.0) check(mod(1.0, -1.0), -0.0) + + def test_equality_rounding(self): + i = int(2 ** 63 - 1) + f = float(i) # not enough precision, becomes 2.0 ** 63 + assert f == 2.0 ** 63 + assert i != f + assert f != i + assert long(i) != f + assert f != long(i) diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -72,7 +72,7 @@ def do_setfield(self, optheap, op): # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structinfo = optheap.ensure_ptr_info_arg0(op) - arg1 = optheap.get_box_replacement(op.getarg(1)) + arg1 = optheap.get_box_replacement(self._getvalue(op)) if self.possible_aliasing(optheap, structinfo): self.force_lazy_setfield(optheap, op.getdescr()) assert not self.possible_aliasing(optheap, structinfo) 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 @@ -2,7 +2,7 @@ from rpython.jit.metainterp.executor import execute_nonspec_const from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\ - ConstIntBound, MININT, MAXINT + ConstIntBound, MININT, MAXINT, IntUnbounded from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.resoperation import rop, AbstractResOp, GuardResOp,\ OpHelpers, ResOperation @@ -57,9 +57,11 @@ if isinstance(op, ConstInt): return ConstIntBound(op.getint()) fw = op.get_forwarded() - if isinstance(fw, IntBound): - return fw - assert fw is None + if fw is not None: + if isinstance(fw, IntBound): + return fw + # rare case: fw might be a RawBufferPtrInfo + return IntUnbounded() assert op.type == 'i' intbound = IntBound(MININT, MAXINT) op.set_forwarded(intbound) @@ -72,7 +74,8 @@ return cur = op.get_forwarded() if cur is not None: - cur.intersect(bound) + if isinstance(cur, IntBound): + cur.intersect(bound) else: op.set_forwarded(bound) @@ -406,7 +409,8 @@ box = self.get_box_replacement(box) if not we_are_translated(): # safety-check if (box.get_forwarded() is not None and - isinstance(constbox, ConstInt)): + isinstance(constbox, ConstInt) and + not isinstance(box.get_forwarded(), info.AbstractRawPtrInfo)): assert box.get_forwarded().contains(constbox.getint()) if box.is_constant(): return 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 @@ -5995,5 +5995,22 @@ """ self.optimize_loop(ops, expected) + def test_remove_multiple_setarrayitems(self): + ops = """ + [p0, i1] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) + guard_value(i1, 42) [] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) # remove this + finish() + """ + expected = """ + [p0, i1] + setarrayitem_gc(p0, 2, NULL, descr=gcarraydescr) + guard_value(i1, 42) [] + finish() + """ + 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 @@ -8906,5 +8906,15 @@ """ self.optimize_loop(ops, expected) + def test_raw_buffer_ptr_info_intbounds_bug(self): + ops = """ + [] + i2 = call_i('malloc', 10, descr=raw_malloc_descr) + guard_value(i2, 12345) [] + jump() + """ + self.optimize_loop(ops, ops) + + class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -256,13 +256,10 @@ offset = offsetbox.getint() # the following check is constant-folded to False if the # translation occurs without any VRawXxxValue instance around - if isinstance(opinfo, info.RawBufferPtrInfo): + if (isinstance(opinfo, info.RawBufferPtrInfo) or + isinstance(opinfo, info.RawSlicePtrInfo)): self.make_virtual_raw_slice(offset, opinfo, op) return - elif isinstance(opinfo, info.RawSlicePtrInfo): - offset = offset + opinfo.offset - self.make_virtual_raw_slice(offset, opinfo.parent, op) - return self.emit_operation(op) def optimize_ARRAYLEN_GC(self, op): 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 @@ -4342,3 +4342,15 @@ self.meta_interp(allfuncs, [9, 2000]) + + def test_unichar_might_be_signed(self): + py.test.skip("wchar_t is sometimes a signed 32-bit integer type, " + "but RPython inteprets it as unsigned (but still " + "translates to wchar_t, so can create confusion)") + def f(x): + return rffi.cast(lltype.Signed, rffi.cast(lltype.UniChar, x)) + res = self.interp_operations(f, [-1]) + if rffi.r_wchar_t.SIGN: + assert res == -1 + else: + assert res == 2 ** 16 - 1 or res == 2 ** 32 - 1 diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -902,39 +902,6 @@ op.args[0]], resultvar=op.result) - def gct_gc_shadowstackref_new(self, hop): - op = hop.spaceop - livevars = self.push_roots(hop) - hop.genop("direct_call", [self.root_walker.gc_shadowstackref_new_ptr], - resultvar=op.result) - self.pop_roots(hop, livevars) - - def gct_gc_shadowstackref_context(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]], - resultvar=op.result) - - def gct_gc_save_current_state_away(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_save_current_state_away_ptr, - op.args[0], op.args[1]]) - - def gct_gc_forget_current_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_forget_current_state_ptr]) - - def gct_gc_restore_state_from(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_restore_state_from_ptr, - op.args[0]]) - - def gct_gc_start_fresh_new_state(self, hop): - hop.genop("direct_call", - [self.root_walker.gc_start_fresh_new_state_ptr]) - def gct_do_malloc_fixedsize(self, hop): # used by the JIT (see rpython.jit.backend.llsupport.gc) op = hop.spaceop diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -180,7 +180,7 @@ thread_stacks[gcdata.active_tid] = old_ref # # no GC operation from here -- switching shadowstack! - shadow_stack_pool.save_current_state_away(old_ref, llmemory.NULL) + shadow_stack_pool.save_current_state_away(old_ref) if new_ref: shadow_stack_pool.restore_state_from(new_ref) else: @@ -219,68 +219,17 @@ minimal_transform=False) def need_stacklet_support(self, gctransformer, getfn): - shadow_stack_pool = self.shadow_stack_pool - SHADOWSTACKREF = get_shadowstackref(self, gctransformer) - - def gc_shadowstackref_new(): - ssref = shadow_stack_pool.allocate(SHADOWSTACKREF) - return lltype.cast_opaque_ptr(llmemory.GCREF, ssref) - - def gc_shadowstackref_context(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - return ssref.context - - def gc_save_current_state_away(gcref, ncontext): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.save_current_state_away(ssref, ncontext) - - def gc_forget_current_state(): - shadow_stack_pool.forget_current_state() - - def gc_restore_state_from(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.restore_state_from(ssref) - - def gc_start_fresh_new_state(): - shadow_stack_pool.start_fresh_new_state() - - s_gcref = SomePtr(llmemory.GCREF) - s_addr = SomeAddress() - self.gc_shadowstackref_new_ptr = getfn(gc_shadowstackref_new, - [], s_gcref, - minimal_transform=False) - self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context, - [s_gcref], s_addr, - inline=True) - self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away, - [s_gcref, s_addr], - annmodel.s_None, - inline=True) - self.gc_forget_current_state_ptr = getfn(gc_forget_current_state, - [], annmodel.s_None, - inline=True) - self.gc_restore_state_from_ptr = getfn(gc_restore_state_from, - [s_gcref], annmodel.s_None, - inline=True) - self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state, - [], annmodel.s_None, - inline=True) + from rpython.rlib import _stacklet_shadowstack + _stacklet_shadowstack.complete_destrptr(gctransformer) # ____________________________________________________________ class ShadowStackPool(object): - """Manages a pool of shadowstacks. The MAX most recently used - shadowstacks are fully allocated and can be directly jumped into - (called "full stacks" below). - The rest are stored in a more virtual-memory-friendly way, i.e. - with just the right amount malloced. Before they can run, they - must be copied into a full shadowstack. + """Manages a pool of shadowstacks. """ _alloc_flavor_ = "raw" root_stack_depth = 163840 - MAX = 20 - def __init__(self, gcdata): self.unused_full_stack = llmemory.NULL self.gcdata = gcdata @@ -293,28 +242,18 @@ """Allocate an empty SHADOWSTACKREF object.""" return lltype.malloc(SHADOWSTACKREF, zero=True) - def save_current_state_away(self, shadowstackref, ncontext): + def save_current_state_away(self, shadowstackref): """Save the current state away into 'shadowstackref'. This either works, or raise MemoryError and nothing is done. To do a switch, first call save_current_state_away() or forget_current_state(), and then call restore_state_from() or start_fresh_new_state(). """ - fresh_free_fullstack = shadowstackref.prepare_free_slot() - if self.unused_full_stack: - if fresh_free_fullstack: - llmemory.raw_free(fresh_free_fullstack) - elif fresh_free_fullstack: - self.unused_full_stack = fresh_free_fullstack - else: - self._prepare_unused_stack() - # + self._prepare_unused_stack() shadowstackref.base = self.gcdata.root_stack_base shadowstackref.top = self.gcdata.root_stack_top - shadowstackref.context = ncontext ll_assert(shadowstackref.base <= shadowstackref.top, "save_current_state_away: broken shadowstack") - shadowstackref.attach() # # cannot use llop.gc_writebarrier() here, because # we are in a minimally-transformed GC helper :-/ @@ -337,7 +276,6 @@ ll_assert(bool(shadowstackref.base), "empty shadowstackref!") ll_assert(shadowstackref.base <= shadowstackref.top, "restore_state_from: broken shadowstack") - self.unused_full_stack = shadowstackref.rebuild(self.unused_full_stack) self.gcdata.root_stack_base = shadowstackref.base self.gcdata.root_stack_top = shadowstackref.top self._cleanup(shadowstackref) @@ -350,127 +288,28 @@ def _cleanup(self, shadowstackref): shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL - shadowstackref.context = llmemory.NULL def _prepare_unused_stack(self): - ll_assert(self.unused_full_stack == llmemory.NULL, - "already an unused_full_stack") - root_stack_size = sizeofaddr * self.root_stack_depth - self.unused_full_stack = llmemory.raw_malloc(root_stack_size) if self.unused_full_stack == llmemory.NULL: - raise MemoryError + root_stack_size = sizeofaddr * self.root_stack_depth + self.unused_full_stack = llmemory.raw_malloc(root_stack_size) + if self.unused_full_stack == llmemory.NULL: + raise MemoryError def get_shadowstackref(root_walker, gctransformer): if hasattr(gctransformer, '_SHADOWSTACKREF'): return gctransformer._SHADOWSTACKREF - # Helpers to same virtual address space by limiting to MAX the - # number of full shadow stacks. If there are more, we compact - # them into a separately-allocated zone of memory of just the right - # size. See the comments in the definition of fullstack_cache below. - - def ll_prepare_free_slot(_unused): - """Free up a slot in the array of MAX entries, ready for storing - a new shadowstackref. Return the memory of the now-unused full - shadowstack. - """ - index = fullstack_cache[0] - if index > 0: - return llmemory.NULL # there is already at least one free slot - # - # make a compact copy in one old entry and return the - # original full-sized memory - index = -index - ll_assert(index > 0, "prepare_free_slot: cache[0] == 0") - compacting = lltype.cast_int_to_ptr(SHADOWSTACKREFPTR, - fullstack_cache[index]) - index += 1 - if index >= ShadowStackPool.MAX: - index = 1 - fullstack_cache[0] = -index # update to the next value in order - # - compacting.detach() - original = compacting.base - size = compacting.top - original - new = llmemory.raw_malloc(size) - if new == llmemory.NULL: - return llmemory.NULL - llmemory.raw_memcopy(original, new, size) - compacting.base = new - compacting.top = new + size - return original - - def ll_attach(shadowstackref): - """After prepare_free_slot(), store a shadowstackref in that slot.""" - index = fullstack_cache[0] - ll_assert(index > 0, "fullstack attach: no free slot") - fullstack_cache[0] = fullstack_cache[index] - fullstack_cache[index] = lltype.cast_ptr_to_int(shadowstackref) - ll_assert(shadowstackref.fsindex == 0, "fullstack attach: already one?") - shadowstackref.fsindex = index # > 0 - - def ll_detach(shadowstackref): - """Detach a shadowstackref from the array of MAX entries.""" - index = shadowstackref.fsindex - ll_assert(index > 0, "detach: unattached shadowstackref") - ll_assert(fullstack_cache[index] == - lltype.cast_ptr_to_int(shadowstackref), - "detach: bad fullstack_cache") - shadowstackref.fsindex = 0 - fullstack_cache[index] = fullstack_cache[0] - fullstack_cache[0] = index - - def ll_rebuild(shadowstackref, fullstack_base): - if shadowstackref.fsindex > 0: - shadowstackref.detach() - return fullstack_base - else: - # make an expanded copy of the compact shadowstack stored in - # 'shadowstackref' and free that - compact = shadowstackref.base - size = shadowstackref.top - compact - shadowstackref.base = fullstack_base - shadowstackref.top = fullstack_base + size - llmemory.raw_memcopy(compact, fullstack_base, size) - llmemory.raw_free(compact) - return llmemory.NULL - SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference()) SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef', - ('base', llmemory.Address), - ('top', llmemory.Address), - ('context', llmemory.Address), - ('fsindex', lltype.Signed), - rtti=True, - adtmeths={'prepare_free_slot': ll_prepare_free_slot, - 'attach': ll_attach, - 'detach': ll_detach, - 'rebuild': ll_rebuild}) + ('base', llmemory.Address), + ('top', llmemory.Address), + rtti=True) SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF) - # Items 1..MAX-1 of the following array can be SHADOWSTACKREF - # addresses cast to integer. Or, they are small numbers and they - # make up a free list, rooted in item 0, which goes on until - # terminated with a negative item. This negative item gives (the - # opposite of) the index of the entry we try to remove next. - # Initially all items are in this free list and the end is '-1'. - fullstack_cache = lltype.malloc(lltype.Array(lltype.Signed), - ShadowStackPool.MAX, - flavor='raw', immortal=True) - for i in range(len(fullstack_cache) - 1): - fullstack_cache[i] = i + 1 - fullstack_cache[len(fullstack_cache) - 1] = -1 - def customtrace(gc, obj, callback, arg): obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR) - index = obj.fsindex - if index > 0: - # Haaaaaaack: fullstack_cache[] is just an integer, so it - # doesn't follow the SHADOWSTACKREF when it moves. But we - # know this customtrace() will be called just after the - # move. So we fix the fullstack_cache[] now... :-/ - fullstack_cache[index] = lltype.cast_ptr_to_int(obj) addr = obj.top start = obj.base while addr != start: @@ -484,22 +323,10 @@ (SHADOWSTACKREF, customtrace)) def shadowstack_destructor(shadowstackref): - if root_walker.stacklet_support: - from rpython.rlib import _rffi_stacklet as _c - h = shadowstackref.context - h = llmemory.cast_adr_to_ptr(h, _c.handle) - shadowstackref.context = llmemory.NULL - # - if shadowstackref.fsindex > 0: - shadowstackref.detach() base = shadowstackref.base shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL llmemory.raw_free(base) - # - if root_walker.stacklet_support: - if h: - _c.destroy(h) destrptr = gctransformer.annotate_helper(shadowstack_destructor, [SHADOWSTACKREFPTR], lltype.Void) diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -1,104 +1,176 @@ from rpython.rlib import _rffi_stacklet as _c from rpython.rlib.debug import ll_assert -from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rlib import rgc +from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.annotator import model as annmodel +from rpython.rtyper.llannotation import lltype_to_annotation -NULL_SUSPSTACK = lltype.nullptr(llmemory.GCREF.TO) +# +# A GC wrapper around the C stacklet handles, with additionally a +# copy of the shadowstack (for all stacklets different than the main) +# +STACKLET = lltype.GcStruct('Stacklet', + ('s_handle', _c.handle), + ('s_sscopy', llmemory.Address), + rtti=True) +STACKLET_PTR = lltype.Ptr(STACKLET) +NULL_STACKLET = lltype.nullptr(STACKLET) +def complete_destrptr(gctransformer): + translator = gctransformer.translator + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + args_s = [lltype_to_annotation(STACKLET_PTR)] + s_result = annmodel.s_None + destrptr = mixlevelannotator.delayedfunction(stacklet_destructor, + args_s, s_result) + mixlevelannotator.finish() + lltype.attachRuntimeTypeInfo(STACKLET, destrptr=destrptr) + +def stacklet_destructor(stacklet): + sscopy = stacklet.s_sscopy + if sscopy: + llmemory.raw_free(sscopy) + h = stacklet.s_handle + if h: + _c.destroy(h) + + +SIZEADDR = llmemory.sizeof(llmemory.Address) + +def customtrace(gc, obj, callback, arg): + stacklet = llmemory.cast_adr_to_ptr(obj, STACKLET_PTR) + sscopy = stacklet.s_sscopy + if sscopy: + length_bytes = sscopy.signed[0] + while length_bytes > 0: + addr = sscopy + length_bytes + gc._trace_callback(callback, arg, addr) + length_bytes -= SIZEADDR +lambda_customtrace = lambda: customtrace + +def sscopy_detach_shadow_stack(): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + top = llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] + length_bytes = top - base + result = llmemory.raw_malloc(SIZEADDR + length_bytes) + if result: + result.signed[0] = length_bytes + llmemory.raw_memcopy(base, result + SIZEADDR, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = base + return result + +def sscopy_attach_shadow_stack(sscopy): + base = llop.gc_adr_of_root_stack_base(llmemory.Address).address[0] + ll_assert(llop.gc_adr_of_root_stack_top(llmemory.Address).address[0]==base, + "attach_shadow_stack: ss is not empty?") + length_bytes = sscopy.signed[0] + llmemory.raw_memcopy(sscopy + SIZEADDR, base, length_bytes) + llop.gc_adr_of_root_stack_top(llmemory.Address).address[0] = ( + base + length_bytes) + llmemory.raw_free(sscopy) + +def alloc_stacklet(): + new_stacklet = lltype.malloc(STACKLET) + new_stacklet.s_handle = _c.null_handle + return new_stacklet + +def attach_handle_on_stacklet(stacklet, h): + if not h: + raise MemoryError + elif _c.is_empty_handle(h): + ll_assert(gcrootfinder.sscopy == llmemory.NULL, + "empty_handle but sscopy != NULL") + return NULL_STACKLET + else: + # This is a return that gave us a real handle. Store it. + stacklet.s_handle = h + stacklet.s_sscopy = gcrootfinder.sscopy + ll_assert(gcrootfinder.sscopy != llmemory.NULL, + "!empty_handle but sscopy == NULL") + gcrootfinder.sscopy = llmemory.NULL + llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(stacklet)) + return stacklet + +def consume_stacklet(stacklet): + h = stacklet.s_handle + ll_assert(bool(h), "consume_stacklet: null handle") + stacklet.s_handle = _c.null_handle + stacklet.s_sscopy = llmemory.NULL + return h + def _new_callback(h, arg): - # We still have the old shadowstack active at this point; save it - # away, and start a fresh new one - oldsuspstack = gcrootfinder.oldsuspstack - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, - oldsuspstack, h) - llop.gc_start_fresh_new_state(lltype.Void) - gcrootfinder.oldsuspstack = NULL_SUSPSTACK + # There is a fresh stacklet object waiting on the gcrootfinder, + # so populate it with data that represents the parent suspended + # stacklet and detach the stacklet object from gcrootfinder. + stacklet = gcrootfinder.fresh_stacklet + gcrootfinder.fresh_stacklet = NULL_STACKLET + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #1") + stacklet = attach_handle_on_stacklet(stacklet, h) + ll_assert(stacklet != NULL_STACKLET, "_new_callback: NULL #2") # - newsuspstack = gcrootfinder.callback(oldsuspstack, arg) + # Call the main function provided by the (RPython) user. + stacklet = gcrootfinder.runfn(stacklet, arg) # - # Finishing this stacklet. - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = newsuspstack - h = llop.gc_shadowstackref_context(llmemory.Address, newsuspstack) - return llmemory.cast_adr_to_ptr(h, _c.handle) + # Here, 'stacklet' points to the target stacklet to which we want + # to jump to next. Read the 'handle' and forget about the + # stacklet object. + gcrootfinder.sscopy = llmemory.NULL + return consume_stacklet(stacklet) -def prepare_old_suspstack(): - if not gcrootfinder.oldsuspstack: # else reuse the one still there - _allocate_old_suspstack() +def _new(thread_handle, arg): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) + sscopy_attach_shadow_stack(sscopy) + return h +_new._dont_inline_ = True -def _allocate_old_suspstack(): - suspstack = llop.gc_shadowstackref_new(llmemory.GCREF) - gcrootfinder.oldsuspstack = suspstack -_allocate_old_suspstack._dont_inline_ = True - -def get_result_suspstack(h): - # Now we are in the target, after the switch() or the new(). - # Note that this whole module was carefully written in such a way as - # not to invoke pushing/popping things off the shadowstack at - # unexpected moments... - oldsuspstack = gcrootfinder.oldsuspstack - newsuspstack = gcrootfinder.newsuspstack - gcrootfinder.oldsuspstack = NULL_SUSPSTACK - gcrootfinder.newsuspstack = NULL_SUSPSTACK - if not h: - raise MemoryError - # We still have the old shadowstack active at this point; save it - # away, and restore the new one - if oldsuspstack: - ll_assert(not _c.is_empty_handle(h),"unexpected empty stacklet handle") - h = llmemory.cast_ptr_to_adr(h) - llop.gc_save_current_state_away(lltype.Void, oldsuspstack, h) - else: - ll_assert(_c.is_empty_handle(h),"unexpected non-empty stacklet handle") - llop.gc_forget_current_state(lltype.Void) - # - llop.gc_restore_state_from(lltype.Void, newsuspstack) - # - # From this point on, 'newsuspstack' is consumed and done, its - # shadow stack installed as the current one. It should not be - # used any more. For performance, we avoid it being deallocated - # by letting it be reused on the next switch. - gcrootfinder.oldsuspstack = newsuspstack - # Return. - return oldsuspstack +def _switch(h): + # No shadowstack manipulation here (no usage of gc references) + sscopy = sscopy_detach_shadow_stack() + gcrootfinder.sscopy = sscopy + if not sscopy: + return _c.null_handle + h = _c.switch(h) + sscopy_attach_shadow_stack(sscopy) + return h +_switch._dont_inline_ = True class StackletGcRootFinder(object): - def new(thrd, callback, arg): - gcrootfinder.callback = callback - thread_handle = thrd._thrd - prepare_old_suspstack() - h = _c.new(thread_handle, llhelper(_c.run_fn, _new_callback), arg) - return get_result_suspstack(h) - new._dont_inline_ = True - new = staticmethod(new) - - def switch(suspstack): - # suspstack has a handle to target, i.e. where to switch to - ll_assert(suspstack != gcrootfinder.oldsuspstack, - "stacklet: invalid use") - gcrootfinder.newsuspstack = suspstack - h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) - h = llmemory.cast_adr_to_ptr(h, _c.handle) - prepare_old_suspstack() - h = _c.switch(h) - return get_result_suspstack(h) - switch._dont_inline_ = True - switch = staticmethod(switch) + fresh_stacklet = NULL_STACKLET @staticmethod - def is_empty_handle(suspstack): - return not suspstack + def new(thrd, callback, arg): + rgc.register_custom_trace_hook(STACKLET, lambda_customtrace) + result_stacklet = alloc_stacklet() + gcrootfinder.fresh_stacklet = alloc_stacklet() + gcrootfinder.runfn = callback + thread_handle = thrd._thrd + h = _new(thread_handle, arg) + return attach_handle_on_stacklet(result_stacklet, h) + + @staticmethod + def switch(stacklet): + # 'stacklet' has a handle to target, i.e. where to switch to + h = consume_stacklet(stacklet) + h = _switch(h) + return attach_handle_on_stacklet(stacklet, h) + + @staticmethod + def is_empty_handle(stacklet): + return not stacklet @staticmethod def get_null_handle(): - return NULL_SUSPSTACK + return NULL_STACKLET gcrootfinder = StackletGcRootFinder() -gcrootfinder.oldsuspstack = NULL_SUSPSTACK -gcrootfinder.newsuspstack = NULL_SUSPSTACK diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -890,19 +890,6 @@ def op_gc_reattach_callback_pieces(self): raise NotImplementedError("gc_reattach_callback_pieces") - def op_gc_shadowstackref_new(self): # stacklet+shadowstack - raise NotImplementedError("gc_shadowstackref_new") - def op_gc_shadowstackref_context(self): - raise NotImplementedError("gc_shadowstackref_context") - def op_gc_save_current_state_away(self): - raise NotImplementedError("gc_save_current_state_away") - def op_gc_forget_current_state(self): - raise NotImplementedError("gc_forget_current_state") - def op_gc_restore_state_from(self): - raise NotImplementedError("gc_restore_state_from") - def op_gc_start_fresh_new_state(self): - raise NotImplementedError("gc_start_fresh_new_state") - def op_gc_get_type_info_group(self): raise NotImplementedError("gc_get_type_info_group") 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 @@ -521,14 +521,6 @@ 'gc_detach_callback_pieces': LLOp(), 'gc_reattach_callback_pieces': LLOp(), - # for stacklet+shadowstack support - 'gc_shadowstackref_new': LLOp(canmallocgc=True), - 'gc_shadowstackref_context': LLOp(), - 'gc_save_current_state_away': LLOp(), - 'gc_forget_current_state': LLOp(), - 'gc_restore_state_from': LLOp(), - 'gc_start_fresh_new_state': LLOp(), - # NOTE NOTE NOTE! don't forget *** canmallocgc=True *** for anything that # can malloc a GC object. From noreply at buildbot.pypy.org Sun Sep 27 20:40:16 2015 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 27 Sep 2015 20:40:16 +0200 (CEST) Subject: [pypy-commit] pypy default: Comment Message-ID: <20150927184016.4A2BD1C0162@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79872:341417fe59f5 Date: 2015-09-27 20:40 +0200 http://bitbucket.org/pypy/pypy/changeset/341417fe59f5/ Log: Comment 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 @@ -8909,6 +8909,8 @@ guard_value(i2, 12345) [] jump() """ + # getting InvalidLoop would be a good idea, too. + # (this test was written to show it would previously crash) self.optimize_loop(ops, ops) From noreply at buildbot.pypy.org Sun Sep 27 22:19:02 2015 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 27 Sep 2015 22:19:02 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: disable debug_prints Message-ID: <20150927201902.EBF8A1C0FEA@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79873:0f368155651f Date: 2015-09-27 22:19 +0200 http://bitbucket.org/pypy/pypy/changeset/0f368155651f/ Log: disable debug_prints 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 @@ -504,8 +504,8 @@ def propagate_all_forward(self, inputargs, ops, call_pure_results=None, rename_inputargs=True, flush=True, origin_jitcode=None, origin_pc=0): - if origin_jitcode is not None: - debug_print("looking for guard at %s %d" % (origin_jitcode.name, origin_pc)) + #if origin_jitcode is not None: + # debug_print("looking for guard at %s %d" % (origin_jitcode.name, origin_pc)) self.origin_jitcode = None # origin_jitcode self.origin_pc = origin_pc if rename_inputargs: 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 @@ -2476,7 +2476,7 @@ if isinstance(resumedescr, compile.ResumeGuardDescr): name = resumedescr.rd_frame_info_list.jitcode.name pc = resumedescr.rd_frame_info_list.pc - debug_print("resuming at %d %s %d" % (name, pc, compute_unique_id(resumedescr))) + #debug_print("resuming at %d %s %d" % (name, pc, compute_unique_id(resumedescr))) if isinstance(resumedescr, compile.ResumeGuardExcDescr): if exception: self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, From noreply at buildbot.pypy.org Mon Sep 28 09:07:00 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 28 Sep 2015 09:07:00 +0200 (CEST) Subject: [pypy-commit] pypy default: Avoid two large constants Message-ID: <20150928070700.8AB941C0FEA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79874:650fe2c7926c Date: 2015-09-28 09:07 +0200 http://bitbucket.org/pypy/pypy/changeset/650fe2c7926c/ Log: Avoid two large constants diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -123,7 +123,7 @@ f1 = self.floatval i2 = space.int_w(w_other) # (double-)floats have always at least 48 bits of precision - if LONG_BIT > 32 and not int_between((-1)<<48, i2, 1<<48): + if LONG_BIT > 32 and not int_between(-1, i2 >> 48, 1): res = do_compare_bigint(f1, rbigint.fromint(i2)) else: f2 = float(i2) From noreply at buildbot.pypy.org Mon Sep 28 09:10:34 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 28 Sep 2015 09:10:34 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: kill the feature of removing guards for now, since it seems to be a bit too fragile Message-ID: <20150928071034.ECE191C0162@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79875:18f9fb59e58b Date: 2015-09-28 09:10 +0200 http://bitbucket.org/pypy/pypy/changeset/18f9fb59e58b/ Log: kill the feature of removing guards for now, since it seems to be a bit too fragile diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -288,29 +288,7 @@ cf = submap[index] = ArrayCachedField(index) return cf - def emit_operation(self, op): - if op.is_guard(): - assert isinstance(op, GuardResOp) - origin_jitcode = self.optimizer.origin_jitcode - origin_pc = self.optimizer.origin_pc - if origin_jitcode is not None: - if (origin_jitcode is op.rd_frame_info_list.jitcode and - origin_pc == op.rd_frame_info_list.pc): - self.optimizer.origin_jitcode = None - self.optimizer.origin_pc = 0 - elif op.getopnum() == rop.GUARD_NO_OVERFLOW: - if self.postponed_op: - # XXX is this always the case? - assert self.postponed_op.is_ovf() - newop = self.optimizer.replace_op_with_no_ovf( - self.postponed_op) - self.postponed_op = newop - else: - self.optimizer.potentially_change_ovf_op_to_no_ovf(op) - return # we optimize the guard - elif op.getopnum() != rop.GUARD_OVERFLOW: - return - + def emit_operation(self, op): self.emitting_operation(op) self.emit_postponed_op() if (op.is_comparison() or op.is_call_may_force() 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 @@ -504,10 +504,6 @@ def propagate_all_forward(self, inputargs, ops, call_pure_results=None, rename_inputargs=True, flush=True, origin_jitcode=None, origin_pc=0): - #if origin_jitcode is not None: - # debug_print("looking for guard at %s %d" % (origin_jitcode.name, origin_pc)) - self.origin_jitcode = None # origin_jitcode - self.origin_pc = origin_pc if rename_inputargs: newargs = [] for inparg in inputargs: @@ -533,9 +529,6 @@ if extra_jump: self.first_optimization.propagate_forward(ops[-1]) self.resumedata_memo.update_counters(self.metainterp_sd.profiler) - - if self.origin_jitcode is not None: - raise Exception("Was looking for guard never foudnd it") return (BasicLoopInfo(newargs, self.quasi_immutable_deps), self._newoperations) 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 @@ -2473,10 +2473,6 @@ def prepare_resume_from_failure(self, deadframe, resumedescr): exception = self.cpu.grab_exc_value(deadframe) - if isinstance(resumedescr, compile.ResumeGuardDescr): - name = resumedescr.rd_frame_info_list.jitcode.name - pc = resumedescr.rd_frame_info_list.pc - #debug_print("resuming at %d %s %d" % (name, pc, compute_unique_id(resumedescr))) if isinstance(resumedescr, compile.ResumeGuardExcDescr): if exception: self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR, diff --git a/rpython/jit/metainterp/test/test_loop.py b/rpython/jit/metainterp/test/test_loop.py --- a/rpython/jit/metainterp/test/test_loop.py +++ b/rpython/jit/metainterp/test/test_loop.py @@ -1089,9 +1089,9 @@ self.meta_interp(f, [30]) self.check_trace_count(3) -<<<<<<< local def test_sharing_guards(self): + py.test.skip("unimplemented") driver = JitDriver(greens = [], reds = 'auto') def f(i): @@ -1108,8 +1108,6 @@ self.meta_interp(f, [15]) # one guard_false got removed self.check_resops(guard_false=4, guard_true=5) -======= ->>>>>>> other class TestLLtype(LoopTest, LLJitMixin): pass From noreply at buildbot.pypy.org Mon Sep 28 09:16:39 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 28 Sep 2015 09:16:39 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: kill it for good and reenable replacements of guards Message-ID: <20150928071639.822001C0162@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79876:0dcb16c2195c Date: 2015-09-28 09:13 +0200 http://bitbucket.org/pypy/pypy/changeset/0dcb16c2195c/ Log: kill it for good and reenable replacements of guards diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -68,13 +68,11 @@ the label """ def __init__(self, start_label, operations, call_pure_results=None, - enable_opts=None, origin_jitcode=None, origin_pc=0): + enable_opts=None): self.start_label = start_label self.operations = operations self.call_pure_results = call_pure_results self.enable_opts = enable_opts - self.origin_jitcode = origin_jitcode - self.origin_pc = origin_pc def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll): from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer @@ -82,23 +80,19 @@ #assert not unroll opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations) return opt.propagate_all_forward(self.start_label.getarglist(), - self.operations, self.call_pure_results, - origin_jitcode=self.origin_jitcode, origin_pc=self.origin_pc) + self.operations, self.call_pure_results) class BridgeCompileData(CompileData): """ This represents ops() with a jump at the end that goes to some loop, we need to deal with virtual state and inlining of short preamble """ def __init__(self, start_label, operations, call_pure_results=None, - enable_opts=None, inline_short_preamble=False, - origin_jitcode=None, origin_pc=0): + enable_opts=None, inline_short_preamble=False): self.start_label = start_label self.operations = operations self.call_pure_results = call_pure_results self.enable_opts = enable_opts self.inline_short_preamble = inline_short_preamble - self.origin_jitcode = origin_jitcode - self.origin_pc = origin_pc def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll): from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer @@ -107,8 +101,7 @@ return opt.optimize_bridge(self.start_label, self.operations, self.call_pure_results, self.inline_short_preamble, - self.box_names_memo, - self.origin_jitcode, self.origin_pc) + self.box_names_memo) class UnrolledLoopData(CompileData): """ This represents label() ops jump with extra info that's from the @@ -682,13 +675,10 @@ class ResumeGuardDescr(ResumeDescr): _attrs_ = ('rd_numb', 'rd_count', 'rd_consts', 'rd_virtuals', - 'rd_frame_info_list', 'rd_pendingfields', 'status', - 'rd_origin_jitcode', 'rd_origin_pc') + 'rd_frame_info_list', 'rd_pendingfields', 'status') rd_numb = lltype.nullptr(NUMBERING) rd_count = 0 - rd_origin_pc = 0 - rd_origin_jitcode = None rd_consts = None rd_virtuals = None rd_frame_info_list = None @@ -696,9 +686,6 @@ status = r_uint(0) - def get_origin_data(self): - return self.rd_origin_jitcode, self.rd_origin_pc - def copy_all_attributes_from(self, other): assert isinstance(other, ResumeGuardDescr) self.rd_count = other.rd_count @@ -943,9 +930,6 @@ def __init__(self, original_greenkey): self.original_greenkey = original_greenkey - def get_origin_data(self): - return None, 0 - def compile_and_attach(self, metainterp, new_loop, orig_inputargs): # We managed to create a bridge going from the interpreter # to previously-compiled code. We keep 'new_loop', which is not @@ -991,20 +975,15 @@ call_pure_results = metainterp.call_pure_results - origin_jitcode, origin_pc = resumekey.get_origin_data() if operations[-1].getopnum() == rop.JUMP: data = BridgeCompileData(label, operations[:], call_pure_results=call_pure_results, enable_opts=enable_opts, - inline_short_preamble=inline_short_preamble, - origin_jitcode=origin_jitcode, - origin_pc=origin_pc) + inline_short_preamble=inline_short_preamble) else: data = SimpleCompileData(label, operations[:], call_pure_results=call_pure_results, - enable_opts=enable_opts, - origin_jitcode=origin_jitcode, - origin_pc=origin_pc) + enable_opts=enable_opts) try: info, newops = optimize_trace(metainterp_sd, jitdriver_sd, data, metainterp.box_names_memo) 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 @@ -502,8 +502,7 @@ return CONST_0 def propagate_all_forward(self, inputargs, ops, call_pure_results=None, - rename_inputargs=True, flush=True, - origin_jitcode=None, origin_pc=0): + rename_inputargs=True, flush=True): if rename_inputargs: newargs = [] for inparg in inputargs: @@ -648,8 +647,6 @@ descr.store_final_boxes(guard_op, last_guard_op.getfailargs(), self.metainterp_sd) assert isinstance(guard_op, GuardResOp) - descr.rd_origin_jitcode = guard_op.rd_frame_info_list.jitcode - descr.rd_origin_pc = guard_op.rd_frame_info_list.pc if guard_op.getopnum() == rop.GUARD_VALUE: guard_op = self._maybe_replace_guard_value(guard_op, descr) return guard_op diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -380,10 +380,8 @@ raise InvalidLoop("promote of a virtual") old_guard_op = info.get_last_guard(self.optimizer) if old_guard_op is not None: - pass - # disable it for now because of sharing - #op = self.replace_guard_class_with_guard_value(op, info, - # old_guard_op) + op = self.replace_guard_class_with_guard_value(op, info, + old_guard_op) elif arg0.type == 'f': arg0 = self.get_box_replacement(arg0) if arg0.is_constant(): diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -223,14 +223,12 @@ return label_vs def optimize_bridge(self, start_label, operations, call_pure_results, - inline_short_preamble, box_names_memo, - origin_jitcode=None, origin_pc=0): + inline_short_preamble, box_names_memo): self._check_no_forwarding([start_label.getarglist(), operations]) info, ops = self.optimizer.propagate_all_forward( start_label.getarglist()[:], operations[:-1], - call_pure_results, True, origin_jitcode=origin_jitcode, - origin_pc=origin_pc) + call_pure_results, True) jump_op = operations[-1] cell_token = jump_op.getdescr() assert isinstance(cell_token, JitCellToken) 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 @@ -1479,7 +1479,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_class=4, guard_value=6) + self.check_resops(guard_class=6, guard_value=6) def test_merge_guardnonnull_guardclass(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'l']) From noreply at buildbot.pypy.org Mon Sep 28 09:16:41 2015 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 28 Sep 2015 09:16:41 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix tests Message-ID: <20150928071641.979A41C0162@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79877:29317cd667c5 Date: 2015-09-28 09:16 +0200 http://bitbucket.org/pypy/pypy/changeset/29317cd667c5/ Log: fix tests diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -411,7 +411,6 @@ # not put in short preambles guard_xxx and guard_value # on the same box. self.optimizer.replace_guard(op, info) - descr.make_a_counter_per_value(op) # to be safe info.reset_last_guard_pos() return op 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 @@ -1479,7 +1479,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_class=6, guard_value=6) + self.check_resops(guard_class=0, guard_value=6) def test_merge_guardnonnull_guardclass(self): myjitdriver = JitDriver(greens = [], reds = ['x', 'l']) @@ -1534,7 +1534,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_value=4, guard_class=0, guard_nonnull=6, + self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4, guard_nonnull_class=0, guard_isnull=2) @@ -1562,7 +1562,7 @@ return x res = self.meta_interp(f, [299], listops=True) assert res == f(299) - self.check_resops(guard_value=4, guard_class=0, guard_nonnull=6, + self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4, guard_nonnull_class=0, guard_isnull=2) @@ -1594,7 +1594,7 @@ res = self.meta_interp(f, [399], listops=True) assert res == f(399) self.check_resops(guard_class=0, guard_nonnull=6, guard_value=6, - guard_nonnull_class=4, guard_isnull=2) + guard_nonnull_class=0, guard_isnull=2) def test_residual_call_doesnt_lose_info(self): @@ -2072,7 +2072,7 @@ assert res == 7068153 self.check_trace_count(6) self.check_resops(guard_true=8, guard_class=2, int_mul=3, - int_add=3, guard_false=3) + int_add=3, guard_false=4) def test_dont_trace_every_iteration(self): myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa']) From noreply at buildbot.pypy.org Mon Sep 28 10:35:21 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 28 Sep 2015 10:35:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Tweak the RPython and PyPy ord() to behave like CPython's when given Message-ID: <20150928083521.74B3B1C134D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79878:47c87779c73a Date: 2015-09-28 10:35 +0200 http://bitbucket.org/pypy/pypy/changeset/47c87779c73a/ Log: Tweak the RPython and PyPy ord() to behave like CPython's when given strange inputs: never return negative numbers on 64-bit. Also fix the repr() of unicodes containing such a character. (Tested in the array module because it's hard to make invalid unichars otherwise.) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -844,6 +844,18 @@ b.byteswap() assert a != b + def test_unicode_ord_positive(self): + import sys + if sys.maxunicode == 0xffff: + skip("test for 32-bit unicodes") + a = self.array('u', '\xff\xff\xff\xff') + assert len(a) == 1 + assert repr(a[0]) == "u'\Uffffffff'" + if sys.maxint == 2147483647: + assert ord(a[0]) == -1 + else: + assert ord(a[0]) == 4294967295 + def test_weakref(self): import weakref a = self.array('c', 'Hi!') diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -652,11 +652,11 @@ def len(self): return immutablevalue(1) +class __extend__(SomeChar): + def ord(self): return SomeInteger(nonneg=True) -class __extend__(SomeChar): - def method_isspace(self): return s_Bool @@ -675,6 +675,13 @@ def method_upper(self): return self +class __extend__(SomeUnicodeCodePoint): + + def ord(self): + # warning, on 32-bit with 32-bit unichars, this might return + # negative numbers + return SomeInteger() + class __extend__(SomeIterator): def iter(self): 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 @@ -4320,14 +4320,14 @@ self.meta_interp(allfuncs, [9, 2000]) - def test_unichar_might_be_signed(self): - py.test.skip("wchar_t is sometimes a signed 32-bit integer type, " - "but RPython inteprets it as unsigned (but still " - "translates to wchar_t, so can create confusion)") + def test_unichar_ord_is_never_signed_on_64bit(self): + import sys + if sys.maxunicode == 0xffff: + py.test.skip("test for 32-bit unicodes") def f(x): - return rffi.cast(lltype.Signed, rffi.cast(lltype.UniChar, x)) + return ord(rffi.cast(lltype.UniChar, x)) res = self.interp_operations(f, [-1]) - if rffi.r_wchar_t.SIGN: + if sys.maxint == 2147483647: assert res == -1 else: - assert res == 2 ** 16 - 1 or res == 2 ** 32 - 1 + assert res == 4294967295 diff --git a/rpython/rlib/runicode.py b/rpython/rlib/runicode.py --- a/rpython/rlib/runicode.py +++ b/rpython/rlib/runicode.py @@ -1403,11 +1403,10 @@ result.append(CHR(quote)) return result.build() + TABLE = STR('0123456789abcdef') + def char_escape_helper(result, char): - num = hex(char) - if STR is unicode: - num = num.decode('ascii') - if char >= 0x10000: + if char >= 0x10000 or char < 0: result.append(STR("\\U")) zeros = 8 elif char >= 0x100: @@ -1416,11 +1415,8 @@ else: result.append(STR("\\x")) zeros = 2 - lnum = len(num) - nb = zeros + 2 - lnum # num starts with '0x' - if nb > 0: - result.append_multiple_char(STR('0'), nb) - result.append_slice(num, 2, lnum) + for i in range(zeros-1, -1, -1): + result.append(TABLE[(char >> (4 * i)) & 0x0f]) return unicode_escape, char_escape_helper diff --git a/rpython/translator/c/src/int.h b/rpython/translator/c/src/int.h --- a/rpython/translator/c/src/int.h +++ b/rpython/translator/c/src/int.h @@ -231,8 +231,12 @@ #define OP_TRUNCATE_LONGLONG_TO_INT(x,r) r = (Signed)(x) #define OP_TRUNCATE_LONGLONGLONG_TO_INT(x,r) r = (Signed)(x) -#define OP_CAST_UNICHAR_TO_INT(x,r) r = (Signed)((Unsigned)(x)) /*?*/ -#define OP_CAST_INT_TO_UNICHAR(x,r) r = (unsigned int)(x) +/* Casting from UniChar to int goes first via "unsigned int". + On 64-bit platforms, this forces a signed 32-bit wchar_t + to an unsigned integer, which is also what CPython's ord() + does. */ +#define OP_CAST_UNICHAR_TO_INT(x,r) r = ((unsigned int)(x)) +#define OP_CAST_INT_TO_UNICHAR(x,r) r = (x) /* bool operations */ From noreply at buildbot.pypy.org Mon Sep 28 12:25:00 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 28 Sep 2015 12:25:00 +0200 (CEST) Subject: [pypy-commit] pypy default: Marginal improvement Message-ID: <20150928102500.F12671C023F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79879:17cf8dc91402 Date: 2015-09-28 12:25 +0200 http://bitbucket.org/pypy/pypy/changeset/17cf8dc91402/ Log: Marginal improvement diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1073,7 +1073,6 @@ genop_nursery_ptr_increment = _binaryop_or_lea('ADD', is_add=True) genop_int_sub = _binaryop_or_lea("SUB", is_add=False) genop_int_mul = _binaryop("IMUL") - genop_int_and = _binaryop("AND") genop_int_or = _binaryop("OR") genop_int_xor = _binaryop("XOR") genop_int_lshift = _binaryop("SHL") @@ -1084,6 +1083,15 @@ genop_float_mul = _binaryop('MULSD') genop_float_truediv = _binaryop('DIVSD') + def genop_int_and(self, op, arglocs, result_loc): + arg1 = arglocs[1] + if IS_X86_64 and (isinstance(arg1, ImmedLoc) and + arg1.value == (1 << 32) - 1): + # special case + self.mc.MOV32(arglocs[0], arglocs[0]) + else: + self.mc.AND(arglocs[0], arg1) + genop_int_lt = _cmpop("L", "G") genop_int_le = _cmpop("LE", "GE") genop_int_eq = _cmpop("E", "E") diff --git a/rpython/jit/backend/x86/test/test_runner.py b/rpython/jit/backend/x86/test/test_runner.py --- a/rpython/jit/backend/x86/test/test_runner.py +++ b/rpython/jit/backend/x86/test/test_runner.py @@ -272,6 +272,17 @@ 'void', ofsi) assert p.i == 3**33 + def test_and_mask_common_patterns(self): + cases = [8, 16, 24] + if WORD == 8: + cases.append(32) + for i in cases: + box = InputArgInt(0xAAAAAAAAAAAA) + res = self.execute_operation(rop.INT_AND, + [box, ConstInt(2 ** i - 1)], + 'int') + assert res == 0xAAAAAAAAAAAA & (2 ** i - 1) + def test_nullity_with_guard(self): allops = [rop.INT_IS_TRUE] guards = [rop.GUARD_TRUE, rop.GUARD_FALSE] From noreply at buildbot.pypy.org Mon Sep 28 13:21:48 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 28 Sep 2015 13:21:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Another performance boost to the common case of zip(). Message-ID: <20150928112148.A672C1C120E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79880:5348f162bc84 Date: 2015-09-28 13:22 +0200 http://bitbucket.org/pypy/pypy/changeset/5348f162bc84/ Log: Another performance boost to the common case of zip(). diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -5,6 +5,7 @@ from __future__ import with_statement import operator from __pypy__ import resizelist_hint, newlist_hint +from __pypy__ import specialized_zip_2_lists # ____________________________________________________________ @@ -217,11 +218,16 @@ in length to the length of the shortest argument sequence.""" l = len(sequences) if l == 2: + # A very fast path if the two sequences are lists + seq0 = sequences[0] + seq1 = sequences[1] + try: + return specialized_zip_2_lists(seq0, seq1) + except TypeError: + pass # This is functionally the same as the code below, but more # efficient because it unrolls the loops over 'sequences'. # Only for two arguments, which is the most common case. - seq0 = sequences[0] - seq1 = sequences[1] iter0 = iter(seq0) iter1 = iter(seq1) hint = min(100000000, # max 100M diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -83,6 +83,7 @@ 'newdict' : 'interp_dict.newdict', 'reversed_dict' : 'interp_dict.reversed_dict', 'strategy' : 'interp_magic.strategy', # dict,set,list + 'specialized_zip_2_lists' : 'interp_magic.specialized_zip_2_lists', 'set_debug' : 'interp_magic.set_debug', 'locals_to_fast' : 'interp_magic.locals_to_fast', 'save_module_content_for_future_reload': diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -147,3 +147,7 @@ @unwrap_spec(w_module=MixedModule) def save_module_content_for_future_reload(space, w_module): w_module.save_module_content_for_future_reload() + +def specialized_zip_2_lists(space, w_list1, w_list2): + from pypy.objspace.std.specialisedtupleobject import specialized_zip_2_lists + return specialized_zip_2_lists(space, w_list1, w_list2) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,7 +1,7 @@ from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.util import negate -from rpython.rlib.objectmodel import compute_hash +from rpython.rlib.objectmodel import compute_hash, specialize from rpython.rlib.rarithmetic import intmask from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name @@ -146,3 +146,64 @@ return Cls_oo(space, w_arg1, w_arg2) else: raise NotSpecialised + +# -------------------------------------------------- +# Special code based on list strategies to implement zip(), +# here with two list arguments only. This builds a zipped +# list that differs from what the app-level code would build: +# if the source lists contain sometimes ints/floats and +# sometimes not, here we will use uniformly 'Cls_oo' instead +# of using 'Cls_ii' or 'Cls_ff' for the elements that match. +# This is a trade-off, but it looks like a good idea to keep +# the list uniform for the JIT---not to mention, it is much +# faster to move the decision out of the loop. + + at specialize.arg(1) +def _build_zipped_spec(space, Cls, lst1, lst2): + length = min(len(lst1), len(lst2)) + return [Cls(space, space.wrap(lst1[i]), + space.wrap(lst2[i])) for i in range(length)] + +def _build_zipped_spec_oo(space, w_list1, w_list2): + strat1 = w_list1.strategy + strat2 = w_list2.strategy + length = min(strat1.length(w_list1), strat2.length(w_list2)) + return [Cls_oo(space, strat1.getitem(w_list1, i), + strat2.getitem(w_list2, i)) for i in range(length)] + +def _build_zipped_unspec(space, w_list1, w_list2): + strat1 = w_list1.strategy + strat2 = w_list2.strategy + length = min(strat1.length(w_list1), strat2.length(w_list2)) + return [space.newtuple([strat1.getitem(w_list1, i), + strat2.getitem(w_list2, i)]) for i in range(length)] + +def specialized_zip_2_lists(space, w_list1, w_list2): + from pypy.objspace.std.listobject import W_ListObject + if (not isinstance(w_list1, W_ListObject) or + not isinstance(w_list2, W_ListObject)): + raise OperationError(space.w_TypeError, + space.wrap("expected two lists")) + + if space.config.objspace.std.withspecialisedtuple: + intlist1 = w_list1.getitems_int() + if intlist1 is not None: + intlist2 = w_list2.getitems_int() + if intlist2 is not None: + lst_w = _build_zipped_spec(space, Cls_ii, intlist1, intlist2) + return space.newlist(lst_w) + else: + floatlist1 = w_list1.getitems_float() + if floatlist1 is not None: + floatlist2 = w_list2.getitems_float() + if floatlist2 is not None: + lst_w = _build_zipped_spec(space, Cls_ff, floatlist1, + floatlist2) + return space.newlist(lst_w) + + lst_w = _build_zipped_spec_oo(space, w_list1, w_list2) + return space.newlist(lst_w) + + else: + lst_w = _build_zipped_unspec(space, w_list1, w_list2) + return space.newlist(lst_w) diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -407,3 +407,21 @@ assert (() != object()) is True assert ((1,) != object()) is True assert ((1, 2) != object()) is True + + def test_zip_two_lists(self): + try: + from __pypy__ import specialized_zip_2_lists + except ImportError: + specialized_zip_2_lists = zip + raises(TypeError, specialized_zip_2_lists, [], ()) + raises(TypeError, specialized_zip_2_lists, (), []) + assert specialized_zip_2_lists([], []) == [ + ] + assert specialized_zip_2_lists([2, 3], []) == [ + ] + assert specialized_zip_2_lists([2, 3], [4, 5, 6]) == [ + (2, 4), (3, 5)] + assert specialized_zip_2_lists([4.1, 3.6, 7.2], [2.3, 4.8]) == [ + (4.1, 2.3), (3.6, 4.8)] + assert specialized_zip_2_lists(["foo", "bar"], [6, 2]) == [ + ("foo", 6), ("bar", 2)] From noreply at buildbot.pypy.org Mon Sep 28 14:12:09 2015 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 28 Sep 2015 14:12:09 +0200 (CEST) Subject: [pypy-commit] jitviewer default: fix Message-ID: <20150928121209.BF1861C0162@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r275:01dbb2d47316 Date: 2015-09-28 14:13 +0200 http://bitbucket.org/pypy/jitviewer/changeset/01dbb2d47316/ Log: fix diff --git a/_jitviewer/display.py b/_jitviewer/display.py --- a/_jitviewer/display.py +++ b/_jitviewer/display.py @@ -26,6 +26,7 @@ html = [] for v in loop.inputargs: #html.append(cssclass(v, v, onmouseover='highlight_var(this)', onmouseout='disable_var(this)')) + v = str(v) html.append(cssclass(v, v, data={'name': v})) self.inputargs = " ".join(html) self.firstlineno = code.co_firstlineno From noreply at buildbot.pypy.org Mon Sep 28 15:09:31 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 28 Sep 2015 15:09:31 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: pushing forward test_zjit on llgraph Message-ID: <20150928130931.8264A1C0162@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79881:8a8e13743c1e Date: 2015-09-28 15:09 +0200 http://bitbucket.org/pypy/pypy/changeset/8a8e13743c1e/ Log: pushing forward test_zjit on llgraph diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -7,6 +7,7 @@ from rpython.jit.backend.x86.test.test_basic import Jit386Mixin from rpython.jit.metainterp.warmspot import reset_jit, get_stats from rpython.jit.metainterp.jitprof import Profiler +from rpython.jit.metainterp import counter from rpython.rlib.jit import Counters from rpython.rlib.rarithmetic import intmask from pypy.module.micronumpy import boxes @@ -17,7 +18,13 @@ from rpython.jit.metainterp import pyjitpl return pyjitpl._warmrunnerdesc.metainterp_sd.profiler -class TestNumpyJit(Jit386Mixin): +class TestNumPyLL(LLJitMixin): + llgraph = True + +class TestNumPyX86(Jit386Mixin): + llgraph = False + +class TestNumpyJit(LLJitMixin): enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll" graph = None interp = None @@ -98,11 +105,11 @@ backendopt=True, graph_and_interp_only=True, ProfilerClass=Profiler, - translate_support_code=True, - translationoptions={'gc':'minimark', - 'gcrootfinder': 'asmgcc', - 'gcremovetypeptr': False - }, + #translate_support_code=True, + #translationoptions={'gc':'minimark', + # 'gcrootfinder': 'asmgcc', + # 'gcremovetypeptr': False + # }, vec=True) self.__class__.interp = interp self.__class__.graph = graph @@ -119,6 +126,8 @@ self.compile_graph() profiler = get_profiler() profiler.start() + from rpython.jit.metainterp import pyjitpl + pyjitpl._warmrunnerdesc.jitcounter = counter.DeterministicJitCounter() reset_jit() i = self.code_mapping[name] retval = self.interp.eval_graph(self.graph, [i]) @@ -162,7 +171,7 @@ def test_float32_add(self): result = self.run("float32_add") self.assert_float_equal(result, 15.0 + 15.0) - self.check_vectorized(2, 2) + self.check_vectorized(1, 1) def define_float_add(): return """ @@ -195,7 +204,7 @@ def test_float32_add_const(self): result = self.run("float32_add_const") self.assert_float_equal(result, 29.0 + 77.345) - self.check_vectorized(2, 2) + self.check_vectorized(1, 1) def define_float_add_const(): return """ @@ -237,7 +246,7 @@ def test_int_expand(self): result = self.run("int_expand") assert int(result) == 7+16+8+16 - self.check_vectorized(2, 2) + self.check_vectorized(1, 1) def define_int32_expand(): return """ @@ -303,7 +312,7 @@ def test_int32_add_const(self): result = self.run("int32_add_const") assert int(result) == 7+1+8+1+11+2+12+2 - self.check_vectorized(2, 2) + self.check_vectorized(1, 1) def define_float_mul_array(): return """ @@ -335,7 +344,7 @@ def test_int32_mul_array(self): result = self.run("int32_mul_array") assert int(result) == 7*7+8*8+11*11+12*12 - self.check_vectorized(2, 2) + self.check_vectorized(1, 1) def define_float32_mul_array(): return """ @@ -363,7 +372,7 @@ def test_conversion(self): result = self.run("conversion") assert result == sum(range(30)) + sum(range(30)) - self.check_vectorized(4, 2) # only sum and astype(int) succeed + self.check_vectorized(2, 2) # only sum and astype(int) succeed def define_sum(): return """ @@ -393,7 +402,7 @@ def test_sum_int(self): result = self.run("sum_int") assert result == sum(range(65)) - self.check_vectorized(2, 2) # 1 sum, 1 for type conversion + self.check_vectorized(1, 1) def define_sum_multi(): return """ @@ -501,7 +510,7 @@ retval = self.interp.eval_graph(self.graph, [i]) # check that we got only one loop assert len(get_stats().loops) == 1 - self.check_vectorized(3, 1) + self.check_vectorized(2, 1) def define_prod(): return """ 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 @@ -839,7 +839,22 @@ return [int(x) ^ int(y) for x,y in zip(vx,vy)] def bh_vec_cast_float_to_singlefloat(self, vx, count): - return vx + from rpython.rlib.rarithmetic import r_singlefloat + return [longlong.singlefloat2int(r_singlefloat(longlong.getrealfloat(v))) + for v in vx] + + def bh_vec_cast_singlefloat_to_float(self, vx, count): + return [longlong.getfloatstorage(float(longlong.int2singlefloat(v))) + for v in vx] + + a = float(a) + return longlong.getfloatstorage(a) + + def bh_vec_cast_float_to_int(self, vx, count): + return [int(x) for x in vx] + + def bh_vec_cast_int_to_float(self, vx, count): + return [float(x) for x in vx] def bh_vec_f(self, count): return [0.0] * count @@ -847,7 +862,8 @@ def bh_vec_i(self, count): return [0] * count - def _bh_vec_pack(self, tv, sv, index, count, _): + def _bh_vec_pack(self, tv, sv, index, count, newcount): + while len(tv) < newcount: tv.append(None) if not isinstance(sv, list): tv[index] = sv return tv @@ -858,7 +874,7 @@ bh_vec_pack_f = _bh_vec_pack bh_vec_pack_i = _bh_vec_pack - def _bh_vec_unpack(self, vx, index, count): + def _bh_vec_unpack(self, vx, index, count, newcount): return vx[index:index+count] bh_vec_unpack_f = _bh_vec_unpack @@ -966,14 +982,15 @@ return hash(self) def setenv(self, box, arg): - if box.is_vector(): + if box.is_vector() and box.count > 1: if box.datatype == INT: - _type = lltype.Signed for i,a in enumerate(arg): if isinstance(a, bool): arg[i] = int(a) + assert all([lltype.typeOf(a) == lltype.Signed for a in arg]) elif box.datatype == FLOAT: - _type = longlong.FLOATSTORAGE + assert all([lltype.typeOf(a) == longlong.FLOATSTORAGE or \ + lltype.typeOf(a) == lltype.Signed for a in arg]) else: raise AssertionError(box) elif box.type == INT: @@ -1429,10 +1446,20 @@ else: new_args = args if opname.startswith('vec_'): + # pre vector op count = self.current_op.count - assert count > 1 + assert count >= 1 new_args = new_args + (count,) - return getattr(self.cpu, 'bh_' + opname)(*new_args) + result = getattr(self.cpu, 'bh_' + opname)(*new_args) + if isinstance(result, list): + # post vector op + count = self.current_op.count + if len(result) > count: + assert count > 0 + result = result[:count] + if count == 1: + result = result[0] + return result execute.func_name = 'execute_' + opname return execute diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -12,6 +12,7 @@ from rpython.rtyper.lltypesystem import rffi from rpython.rtyper.lltypesystem import lltype from rpython.conftest import option +from rpython.jit.metainterp.compile import invent_fail_descr_for_op class FakeDependencyGraph(DependencyGraph): """ A dependency graph that is able to emit every instruction @@ -45,6 +46,9 @@ def parse_loop(self, ops, add_label=True): loop = self.parse(ops, postprocess=self.postprocess) loop.operations = filter(lambda op: op.getopnum() != rop.DEBUG_MERGE_POINT, loop.operations) + #for op in loop.operations: + # if op.is_guard() and op.getdescr() is None: + # op.setdescr(invent_fail_descr_for_op(op.opnum, None)) token = JitCellToken() if add_label: label = ResOperation(rop.LABEL, loop.inputargs, descr=TargetToken(token)) diff --git a/rpython/jit/metainterp/optimizeopt/vector.py b/rpython/jit/metainterp/optimizeopt/vector.py --- a/rpython/jit/metainterp/optimizeopt/vector.py +++ b/rpython/jit/metainterp/optimizeopt/vector.py @@ -555,7 +555,6 @@ self.mark_guard(guard_node, loop) for node in zero_deps.keys(): assert not node.is_imaginary() - print "edge to", node earlyexit.edge_to(node) if one_valid: return graph diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -116,11 +116,6 @@ _mixin_ = True def inittype(self): - if self.returns_void(): - self.bytesize = 0 - self.datatype = 'v' - return - if self.is_primitive_array_access(): from rpython.jit.backend.llsupport.descr import ArrayDescr descr = self.getdescr() @@ -149,31 +144,24 @@ self.setdatatype(tt, self.cast_to_bytesize(), tt == 'i') else: # pass through the type of the first input argument - if self.numargs() == 0: - if self.type == 'i': - self.setdatatype('i', INT_WORD, True) - elif self.type == 'f': - self.setdatatype('f', FLOAT_WORD, False) - return - i = 0 - arg = self.getarg(i) - while arg.is_constant() and i+1 < self.numargs(): - i += 1 + type = self.type + signed = type == 'i' + bytesize = -1 + if self.numargs() > 0: + i = 0 arg = self.getarg(i) - if arg.is_constant() or arg.datatype == '\x00': - if arg.type == 'i': - self.setdatatype('i', INT_WORD, True) - elif arg.type == 'f': - self.setdatatype('f', FLOAT_WORD, False) - else: - assert arg.type == 'r' - self.setdatatype('r', INT_WORD, False) - return - self.setdatatype(arg.datatype, arg.bytesize, arg.signed) + while arg.is_constant() and i+1 < self.numargs(): + i += 1 + arg = self.getarg(i) + if arg.datatype != '\x00' and \ + arg.bytesize != -1: + type = arg.datatype + signed = arg.signed + bytesize = arg.bytesize if self.returns_bool_result(): - self.datatype = 'i' + type = 'i' + self.setdatatype(type, bytesize, signed) assert self.datatype != '\x00' - #assert self.bytesize > 0 def setdatatype(self, data_type, bytesize, signed): self.datatype = data_type @@ -182,6 +170,8 @@ bytesize = INT_WORD elif data_type == 'f': bytesize = FLOAT_WORD + elif data_type == 'v': + bytesize = 0 self.bytesize = bytesize self.signed = signed @@ -1190,10 +1180,10 @@ 'VEC_CAST_FLOAT_TO_INT': ('f', 8, 'i', 4, 2), 'CAST_INT_TO_FLOAT': ('i', 4, 'f', 8, 2), 'VEC_CAST_INT_TO_FLOAT': ('i', 4, 'f', 8, 2), - 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4, 2), - 'VEC_CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'f', 4, 2), - 'CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8, 2), - 'VEC_CAST_SINGLEFLOAT_TO_FLOAT': ('f', 4, 'f', 8, 2), + 'CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'i', 4, 2), + 'VEC_CAST_FLOAT_TO_SINGLEFLOAT': ('f', 8, 'i', 4, 2), + 'CAST_SINGLEFLOAT_TO_FLOAT': ('i', 4, 'f', 8, 2), + 'VEC_CAST_SINGLEFLOAT_TO_FLOAT': ('i', 4, 'f', 8, 2), 'INT_SIGNEXT': ('i', 0, 'i', 0, 0), 'VEC_INT_SIGNEXT': ('i', 0, 'i', 0, 0), } diff --git a/rpython/jit/metainterp/test/test_resoperation.py b/rpython/jit/metainterp/test/test_resoperation.py --- a/rpython/jit/metainterp/test/test_resoperation.py +++ b/rpython/jit/metainterp/test/test_resoperation.py @@ -3,6 +3,8 @@ from rpython.jit.metainterp import resoperation as rop from rpython.jit.metainterp.history import AbstractDescr, AbstractFailDescr from rpython.jit.metainterp.history import ConstInt +from rpython.jit.backend.llsupport.symbolic import (WORD as INT_WORD, + SIZEOF_FLOAT as FLOAT_WORD) def test_arity_mixins(): cases = [ @@ -91,3 +93,13 @@ op = rop.ResOperation(rop.rop.CAST_FLOAT_TO_INT, ['a'], 'c') assert op.casts_box() assert isinstance(op, rop.CastResOp) + +def test_types(): + op = rop.ResOperation(rop.rop.INT_ADD, [ConstInt(0),ConstInt(1)]) + assert op.type == 'i' + assert op.datatype == 'i' + assert op.bytesize == INT_WORD + op = rop.ResOperation(rop.rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT, [op]) + assert op.type == 'i' + assert op.datatype == 'i' + assert op.bytesize == 4 diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py --- a/rpython/jit/metainterp/test/test_resume.py +++ b/rpython/jit/metainterp/test/test_resume.py @@ -1417,7 +1417,8 @@ assert not storage.rd_pendingfields # class FieldDescr(AbstractDescr): - pass + def is_array_of_primitives(self): + return False field_a = FieldDescr() storage = Storage() modifier = ResumeDataVirtualAdder(None, storage, storage, None) diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -177,7 +177,6 @@ def reset_jit(): """Helper for some tests (see micronumpy/test/test_zjit.py)""" - from rpython.jit.metainterp import counter reset_stats() pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear() pyjitpl._warmrunnerdesc.jitcounter._clear_all() From noreply at buildbot.pypy.org Mon Sep 28 16:32:37 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 28 Sep 2015 16:32:37 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: switching from llgraph to x86 backend for zjit Message-ID: <20150928143237.E59051C134D@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79882:5f2180dc8e34 Date: 2015-09-28 16:32 +0200 http://bitbucket.org/pypy/pypy/changeset/5f2180dc8e34/ Log: switching from llgraph to x86 backend for zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -18,13 +18,7 @@ from rpython.jit.metainterp import pyjitpl return pyjitpl._warmrunnerdesc.metainterp_sd.profiler -class TestNumPyLL(LLJitMixin): - llgraph = True - -class TestNumPyX86(Jit386Mixin): - llgraph = False - -class TestNumpyJit(LLJitMixin): +class TestNumpyJit(Jit386Mixin): enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll" graph = None interp = None @@ -105,11 +99,12 @@ backendopt=True, graph_and_interp_only=True, ProfilerClass=Profiler, - #translate_support_code=True, - #translationoptions={'gc':'minimark', - # 'gcrootfinder': 'asmgcc', - # 'gcremovetypeptr': False - # }, + translate_support_code=True, + translationoptions={'gc':'minimark', + 'gcrootfinder': 'asmgcc', + 'gcremovetypeptr': False + }, + deterministic_jit_counter=True, vec=True) self.__class__.interp = interp self.__class__.graph = graph From noreply at buildbot.pypy.org Mon Sep 28 16:35:06 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 28 Sep 2015 16:35:06 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: forgot to remove parameter... Message-ID: <20150928143506.CA8F81C134D@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79883:b6fc67e7c33e Date: 2015-09-28 16:35 +0200 http://bitbucket.org/pypy/pypy/changeset/b6fc67e7c33e/ Log: forgot to remove parameter... diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -104,7 +104,6 @@ 'gcrootfinder': 'asmgcc', 'gcremovetypeptr': False }, - deterministic_jit_counter=True, vec=True) self.__class__.interp = interp self.__class__.graph = graph From noreply at buildbot.pypy.org Mon Sep 28 19:29:57 2015 From: noreply at buildbot.pypy.org (mattip) Date: Mon, 28 Sep 2015 19:29:57 +0200 (CEST) Subject: [pypy-commit] pypy default: redo 399217ef3933 so all tests pass, fix test for upstream compatibility Message-ID: <20150928172957.6B22E1C120E@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r79884:3e89b1604c3c Date: 2015-09-28 20:30 +0300 http://bitbucket.org/pypy/pypy/changeset/3e89b1604c3c/ Log: redo 399217ef3933 so all tests pass, fix test for upstream compatibility diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -117,12 +117,14 @@ return W_NDimArray(impl) @staticmethod - def new_slice(space, offset, strides, backstrides, shape, parent, orig_arr, dtype=None): + def new_slice(space, offset, strides, backstrides, shape, parent, w_arr, dtype=None): from pypy.module.micronumpy import concrete - + w_base = w_arr + if w_arr.implementation.base() is not None: + w_base = w_arr.implementation.base() impl = concrete.SliceArray(offset, strides, backstrides, shape, parent, - orig_arr, dtype) - return wrap_impl(space, space.type(orig_arr), orig_arr, impl) + w_base, dtype) + return wrap_impl(space, space.type(w_arr), w_arr, impl) @staticmethod def new_scalar(space, dtype, w_val=None): diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -568,11 +568,6 @@ self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) except OverflowError: raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") - while orig_arr is not None: - assert isinstance(orig_arr, W_NDimArray) - if orig_arr.implementation.base() is None: - break - orig_arr = orig_arr.implementation.base() self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -133,7 +133,9 @@ return w_arr else: imp = w_object.implementation - w_base = imp.base() or w_object + w_base = w_object + if imp.base() is not None: + w_base = imp.base() with imp as storage: sz = support.product(w_object.get_shape()) * dtype.elsize return W_NDimArray.from_shape_and_storage(space, diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -2519,10 +2519,10 @@ assert b.shape == b[...].shape assert (b == b[...]).all() - a = np.arange(6).reshape(2, 3) + a = np.arange(6) if '__pypy__' in sys.builtin_module_names: raises(ValueError, "a[..., ...]") - b = a [..., 0] + b = a.reshape(2, 3)[..., 0] assert (b == [0, 3]).all() assert b.base is a From noreply at buildbot.pypy.org Mon Sep 28 21:53:54 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Mon, 28 Sep 2015 21:53:54 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: wunderbar! all but one test_zjit test passing Message-ID: <20150928195354.25D461C120E@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79885:bb3eebb00aa2 Date: 2015-09-28 21:54 +0200 http://bitbucket.org/pypy/pypy/changeset/bb3eebb00aa2/ Log: wunderbar! all but one test_zjit test passing diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -18,7 +18,7 @@ from rpython.jit.metainterp import pyjitpl return pyjitpl._warmrunnerdesc.metainterp_sd.profiler -class TestNumpyJit(Jit386Mixin): +class TestNumpyJit(LLJitMixin): enable_opts = "intbounds:rewrite:virtualize:string:earlyforce:pure:heap:unroll" graph = None interp = None @@ -99,11 +99,6 @@ backendopt=True, graph_and_interp_only=True, ProfilerClass=Profiler, - translate_support_code=True, - translationoptions={'gc':'minimark', - 'gcrootfinder': 'asmgcc', - 'gcremovetypeptr': False - }, vec=True) self.__class__.interp = interp self.__class__.graph = graph @@ -120,8 +115,6 @@ self.compile_graph() profiler = get_profiler() profiler.start() - from rpython.jit.metainterp import pyjitpl - pyjitpl._warmrunnerdesc.jitcounter = counter.DeterministicJitCounter() reset_jit() i = self.code_mapping[name] retval = self.interp.eval_graph(self.graph, [i]) @@ -165,7 +158,7 @@ def test_float32_add(self): result = self.run("float32_add") self.assert_float_equal(result, 15.0 + 15.0) - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_float_add(): return """ @@ -198,7 +191,7 @@ def test_float32_add_const(self): result = self.run("float32_add_const") self.assert_float_equal(result, 29.0 + 77.345) - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_float_add_const(): return """ @@ -240,7 +233,7 @@ def test_int_expand(self): result = self.run("int_expand") assert int(result) == 7+16+8+16 - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_int32_expand(): return """ @@ -255,7 +248,7 @@ def test_int32_expand(self): result = self.run("int32_expand") assert int(result) == 7+16+8+16 - self.check_vectorized(2, 2) + self.check_vectorized(2, 1) def define_int16_expand(): return """ @@ -271,7 +264,7 @@ i = 8 assert int(result) == i*16 + sum(range(7,7+i)) # currently is is not possible to accum for types with < 8 bytes - self.check_vectorized(3, 1) + self.check_vectorized(3, 0) def define_int8_expand(): return """ @@ -289,7 +282,7 @@ # neither does sum # a + c should work, but it is given as a parameter # thus the accum must handle this! - self.check_vectorized(3, 1) + self.check_vectorized(3, 0) def define_int32_add_const(): return """ @@ -306,7 +299,7 @@ def test_int32_add_const(self): result = self.run("int32_add_const") assert int(result) == 7+1+8+1+11+2+12+2 - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_float_mul_array(): return """ @@ -338,7 +331,7 @@ def test_int32_mul_array(self): result = self.run("int32_mul_array") assert int(result) == 7*7+8*8+11*11+12*12 - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_float32_mul_array(): return """ @@ -366,7 +359,7 @@ def test_conversion(self): result = self.run("conversion") assert result == sum(range(30)) + sum(range(30)) - self.check_vectorized(2, 2) # only sum and astype(int) succeed + self.check_vectorized(4, 2) # only sum and astype(int) succeed def define_sum(): return """ @@ -396,7 +389,7 @@ def test_sum_int(self): result = self.run("sum_int") assert result == sum(range(65)) - self.check_vectorized(1, 1) + self.check_vectorized(2, 2) def define_sum_multi(): return """ @@ -420,7 +413,9 @@ def test_sum_float_to_int16(self): result = self.run("sum_float_to_int16") assert result == sum(range(30)) - self.check_vectorized(1, 0) + # one can argue that this is not desired, + # but unpacking exactly hits savings = 0 + self.check_vectorized(1, 1) def define_sum_float_to_int32(): return """ a = |30| @@ -504,7 +499,7 @@ retval = self.interp.eval_graph(self.graph, [i]) # check that we got only one loop assert len(get_stats().loops) == 1 - self.check_vectorized(2, 1) + self.check_vectorized(3, 1) def define_prod(): return """ @@ -823,7 +818,7 @@ result = self.run("dot") assert result == 184 self.check_trace_count(4) - self.check_vectorized(3,1) + self.check_vectorized(1,1) def define_argsort(): return """ @@ -923,7 +918,7 @@ def test_dot_matrix(self): result = self.run("dot_matrix") assert int(result) == 86 - self.check_vectorized(2, 1) + self.check_vectorized(1, 1) # NOT WORKING diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -9,6 +9,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.jitexc import NotAProfitableLoop from rpython.rlib.objectmodel import specialize, always_inline +from rpython.jit.metainterp.jitexc import NotAVectorizeableLoop, NotAProfitableLoop class SchedulerState(object): @@ -206,6 +207,25 @@ return self.count return count +class OpRestrict(object): + def __init__(self, argument_restris): + self.argument_restrictions = argument_restris + + def check_operation(self, state, pack, op): + pass + +class OpMatchSizeTypeFirst(OpRestrict): + def check_operation(self, state, pack, op): + arg0 = op.getarg(0) + bytesize = arg0.bytesize + datatype = arg0.datatype + + for arg in op.getarglist(): + if arg.bytesize != bytesize: + raise NotAVectorizeableLoop() + if arg.datatype != datatype: + raise NotAVectorizeableLoop() + class trans(object): TR_ANY = TypeRestrict() @@ -215,43 +235,46 @@ TR_DOUBLE_2 = TypeRestrict(FLOAT, 8, 2) TR_INT32_2 = TypeRestrict(INT, 4, 2) + OR_MSTF_I = OpMatchSizeTypeFirst([TR_ANY_INTEGER, TR_ANY_INTEGER]) + OR_MSTF_F = OpMatchSizeTypeFirst([TR_ANY_FLOAT, TR_ANY_FLOAT]) + # note that the following definition is x86 arch specific MAPPING = { - rop.VEC_INT_ADD: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_SUB: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_MUL: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_AND: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_OR: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_XOR: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_EQ: [TR_ANY_INTEGER, TR_ANY_INTEGER], - rop.VEC_INT_NE: [TR_ANY_INTEGER, TR_ANY_INTEGER], + rop.VEC_INT_ADD: OR_MSTF_I, + rop.VEC_INT_SUB: OR_MSTF_I, + rop.VEC_INT_MUL: OR_MSTF_I, + rop.VEC_INT_AND: OR_MSTF_I, + rop.VEC_INT_OR: OR_MSTF_I, + rop.VEC_INT_XOR: OR_MSTF_I, + rop.VEC_INT_EQ: OR_MSTF_I, + rop.VEC_INT_NE: OR_MSTF_I, - rop.VEC_FLOAT_ADD: [TR_ANY_FLOAT, TR_ANY_FLOAT], - rop.VEC_FLOAT_SUB: [TR_ANY_FLOAT, TR_ANY_FLOAT], - rop.VEC_FLOAT_MUL: [TR_ANY_FLOAT, TR_ANY_FLOAT], - rop.VEC_FLOAT_TRUEDIV: [TR_ANY_FLOAT, TR_ANY_FLOAT], - rop.VEC_FLOAT_ABS: [TR_ANY_FLOAT], - rop.VEC_FLOAT_NEG: [TR_ANY_FLOAT], + rop.VEC_FLOAT_ADD: OR_MSTF_F, + rop.VEC_FLOAT_SUB: OR_MSTF_F, + rop.VEC_FLOAT_MUL: OR_MSTF_F, + rop.VEC_FLOAT_TRUEDIV: OR_MSTF_F, + rop.VEC_FLOAT_ABS: OpRestrict([TR_ANY_FLOAT]), + rop.VEC_FLOAT_NEG: OpRestrict([TR_ANY_FLOAT]), - rop.VEC_RAW_STORE: [None, None, TR_ANY], - rop.VEC_SETARRAYITEM_RAW: [None, None, TR_ANY], - rop.VEC_SETARRAYITEM_GC: [None, None, TR_ANY], + rop.VEC_RAW_STORE: OpRestrict([None, None, TR_ANY]), + rop.VEC_SETARRAYITEM_RAW: OpRestrict([None, None, TR_ANY]), + rop.VEC_SETARRAYITEM_GC: OpRestrict([None, None, TR_ANY]), - rop.GUARD_TRUE: [TR_ANY_INTEGER], - rop.GUARD_FALSE: [TR_ANY_INTEGER], + rop.GUARD_TRUE: OpRestrict([TR_ANY_INTEGER]), + rop.GUARD_FALSE: OpRestrict([TR_ANY_INTEGER]), ## irregular - rop.VEC_INT_SIGNEXT: [TR_ANY_INTEGER], + rop.VEC_INT_SIGNEXT: OpRestrict([TR_ANY_INTEGER]), - rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: [TR_DOUBLE_2], + rop.VEC_CAST_FLOAT_TO_SINGLEFLOAT: OpRestrict([TR_DOUBLE_2]), # weird but the trace will store single floats in int boxes - rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: [TR_INT32_2], - rop.VEC_CAST_FLOAT_TO_INT: [TR_DOUBLE_2], - rop.VEC_CAST_INT_TO_FLOAT: [TR_INT32_2], + rop.VEC_CAST_SINGLEFLOAT_TO_FLOAT: OpRestrict([TR_INT32_2]), + rop.VEC_CAST_FLOAT_TO_INT: OpRestrict([TR_DOUBLE_2]), + rop.VEC_CAST_INT_TO_FLOAT: OpRestrict([TR_INT32_2]), - rop.VEC_FLOAT_EQ: [TR_ANY_FLOAT,TR_ANY_FLOAT], - rop.VEC_FLOAT_NE: [TR_ANY_FLOAT,TR_ANY_FLOAT], - rop.VEC_INT_IS_TRUE: [TR_ANY_INTEGER,TR_ANY_INTEGER], + rop.VEC_FLOAT_EQ: OpRestrict([TR_ANY_FLOAT,TR_ANY_FLOAT]), + rop.VEC_FLOAT_NE: OpRestrict([TR_ANY_FLOAT,TR_ANY_FLOAT]), + rop.VEC_INT_IS_TRUE: OpRestrict([TR_ANY_INTEGER,TR_ANY_INTEGER]), } def turn_into_vector(state, pack): @@ -259,6 +282,9 @@ check_if_pack_supported(state, pack) state.costmodel.record_pack_savings(pack, pack.numops()) left = pack.leftmost() + oprestrict = trans.MAPPING.get(pack.leftmost().vector, None) + if oprestrict is not None: + oprestrict.check_operation(state, pack, left) args = left.getarglist_copy() prepare_arguments(state, pack, args) vecop = VecOperation(left.vector, args, left, @@ -287,9 +313,10 @@ # a) expand vars/consts before the label and add as argument # b) expand vars created in the loop body # - restrictions = trans.MAPPING.get(pack.leftmost().vector, []) - if not restrictions: + oprestrict = trans.MAPPING.get(pack.leftmost().vector, None) + if not oprestrict: return + restrictions = oprestrict.argument_restrictions for i,arg in enumerate(args): if i >= len(restrictions) or restrictions[i] is None: # ignore this argument diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py @@ -1234,6 +1234,23 @@ vopt = self.vectorize(trace) self.assert_equal(trace, trace_opt) + def test_sum_int16_prevent(self): + trace = self.parse_loop(""" + [i0, p1, i2, p3, i4, i5, i6] + i7 = raw_load_i(i5, i4, descr=int16arraydescr) + i8 = int_add(i0, i7) + i10 = int_add(i2, 1) + i12 = int_add(i4, 2) + i13 = int_ge(i10, i6) + guard_false(i13, descr=) [p3, i10, i8, i12, None, p1, None, None] + jump(i8, p1, i10, p3, i12, i5, i6) + """) + try: + vopt = self.vectorize(trace) + py.test.fail() + except NotAVectorizeableLoop: + pass + def test_axis_sum(self): # TODO trace = """ From noreply at buildbot.pypy.org Tue Sep 29 09:07:19 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 09:07:19 +0200 (CEST) Subject: [pypy-commit] pypy release-2.6.x: Move the slow-path loop out of this RPython function Message-ID: <20150929070719.5449A1C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.6.x Changeset: r79886:a85f01242676 Date: 2015-09-29 09:07 +0200 http://bitbucket.org/pypy/pypy/changeset/a85f01242676/ Log: Move the slow-path loop out of this RPython function diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1396,16 +1396,19 @@ else: subitems_w = [self._none_value] * length l = self.unerase(w_list.lstorage) - for i in range(length): - try: - subitems_w[i] = l[start] - start += step - except IndexError: - raise + self._fill_in_with_sliced_items(subitems_w, l, start, step, length) storage = self.erase(subitems_w) return W_ListObject.from_storage_and_strategy( self.space, storage, self) + def _fill_in_with_sliced_items(self, subitems_w, l, start, step, length): + for i in range(length): + try: + subitems_w[i] = l[start] + start += step + except IndexError: + raise + def switch_to_next_strategy(self, w_list, w_sample_item): w_list.switch_to_object_strategy() From noreply at buildbot.pypy.org Tue Sep 29 09:11:27 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 09:11:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Move the slow-path loop out of this RPython function Message-ID: <20150929071127.4ACBA1C0162@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79887:4e688540cfe9 Date: 2015-09-29 09:07 +0200 http://bitbucket.org/pypy/pypy/changeset/4e688540cfe9/ Log: Move the slow-path loop out of this RPython function (oops, didn't mean to check that in branch 'release-2.6.x') diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1396,16 +1396,19 @@ else: subitems_w = [self._none_value] * length l = self.unerase(w_list.lstorage) - for i in range(length): - try: - subitems_w[i] = l[start] - start += step - except IndexError: - raise + self._fill_in_with_sliced_items(subitems_w, l, start, step, length) storage = self.erase(subitems_w) return W_ListObject.from_storage_and_strategy( self.space, storage, self) + def _fill_in_with_sliced_items(self, subitems_w, l, start, step, length): + for i in range(length): + try: + subitems_w[i] = l[start] + start += step + except IndexError: + raise + def switch_to_next_strategy(self, w_list, w_sample_item): w_list.switch_to_object_strategy() From noreply at buildbot.pypy.org Tue Sep 29 10:03:03 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 10:03:03 +0200 (CEST) Subject: [pypy-commit] pypy default: Tweaks to reduce the number of checks with the JIT, notably in 'lst[a:]'. Message-ID: <20150929080303.DA6961C04C6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79888:68b5a3425c05 Date: 2015-09-29 10:03 +0200 http://bitbucket.org/pypy/pypy/changeset/68b5a3425c05/ Log: Tweaks to reduce the number of checks with the JIT, notably in 'lst[a:]'. diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -5,6 +5,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import GetSetProperty, TypeDef from rpython.rlib.objectmodel import specialize +from rpython.rlib import jit class W_SliceObject(W_Root): @@ -234,10 +235,16 @@ assert length >= 0 if start < 0: start = 0 + # hack for the JIT, for slices with no end specified: + # this avoids the two comparisons that follow + if jit.isconstant(stop) and stop == sys.maxint: + return start, length if stop < start: stop = start if stop > length: stop = length - if start > length: + if jit.isconstant(start) and start == 0: + pass # no need to do the following check here + elif start > length: start = length return start, stop From noreply at buildbot.pypy.org Tue Sep 29 10:08:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 10:08:46 +0200 (CEST) Subject: [pypy-commit] pypy default: oups Message-ID: <20150929080846.F1FC11C04C6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79889:c73d06db1bdc Date: 2015-09-29 09:12 +0100 http://bitbucket.org/pypy/pypy/changeset/c73d06db1bdc/ Log: oups diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -1,5 +1,6 @@ """Slice object""" +import sys from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError From noreply at buildbot.pypy.org Tue Sep 29 11:09:11 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 29 Sep 2015 11:09:11 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: fix a test Message-ID: <20150929090911.E942B1C0162@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79890:20620a79a672 Date: 2015-09-29 11:09 +0200 http://bitbucket.org/pypy/pypy/changeset/20620a79a672/ Log: fix a test diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -157,6 +157,9 @@ def __init__(self, identifier=None): self.identifier = identifier # for testing + def make_a_counter_per_value(self, op, index): + pass # for testing + @specialize.argtype(0) def newconst(value): 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 @@ -5035,10 +5035,9 @@ expected = """ [p0] p20 = getfield_gc_r(p0, descr=nextdescr) - guard_nonnull_class(p20, ConstClass(node_vtable)) [] + guard_value(p20, ConstPtr(myptr)) [] p23 = getfield_gc_r(p20, descr=valuedescr) guard_isnull(p23) [] - guard_value(p20, ConstPtr(myptr)) [] p64 = call_may_force_r(NULL, NULL, descr=plaincalldescr) jump(p0) """ From noreply at buildbot.pypy.org Tue Sep 29 11:26:36 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 29 Sep 2015 11:26:36 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: half-heartedly fix the overflow changes in test_random Message-ID: <20150929092637.005F21C06AD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79891:ee21249ebd92 Date: 2015-09-29 11:26 +0200 http://bitbucket.org/pypy/pypy/changeset/ee21249ebd92/ Log: half-heartedly fix the overflow changes in test_random diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -22,6 +22,8 @@ self.operations = subops class FakeMetaInterp(object): + ovf_flag = False + def execute_raised(self, exc, constant=False): self._got_exc = exc @@ -366,8 +368,7 @@ fail_subset = builder.subset_of_intvars(r) original_intvars = builder.intvars[:] super(AbstractOvfOperation, self).produce_into(builder, r) - if builder.fakemetainterp._got_exc: # overflow detected - assert isinstance(builder.fakemetainterp._got_exc, OverflowError) + if builder.fakemetainterp.ovf_flag: # overflow detected op = ResOperation(rop.GUARD_OVERFLOW, []) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including From noreply at buildbot.pypy.org Tue Sep 29 11:32:27 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 11:32:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix: r_wchar_t.SIGN is not useful to know if that type is originally Message-ID: <20150929093227.9DEDF1C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79892:f5b2758482a2 Date: 2015-09-29 11:32 +0200 http://bitbucket.org/pypy/pypy/changeset/f5b2758482a2/ Log: Fix: r_wchar_t.SIGN is not useful to know if that type is originally signed or not diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -7,6 +7,7 @@ from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rfficache from pypy.interpreter.error import oefmt from pypy.module._cffi_backend import cdataobj, misc @@ -130,7 +131,8 @@ # though it may be signed when 'wchar_t' is written to C). WCHAR_INT = {(2, False): rffi.USHORT, (4, False): rffi.UINT, - (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar), rffi.r_wchar_t.SIGN] + (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar), + rfficache.signof_c_type('wchar_t')] WCHAR_INTP = rffi.CArrayPtr(WCHAR_INT) class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar): diff --git a/rpython/rtyper/tool/rfficache.py b/rpython/rtyper/tool/rfficache.py --- a/rpython/rtyper/tool/rfficache.py +++ b/rpython/rtyper/tool/rfficache.py @@ -52,6 +52,17 @@ result.append(int(answer[1])) return result +def signof_c_type(c_typename, **kwds): + question = 'printf("sign %s=%%d\\n", ((%s) -1) <= 0);' % (c_typename, + c_typename) + answer = ask_gcc(question, **kwds).strip() + if answer == 'sign %s=0' % (c_typename,): + return False + if answer == 'sign %s=1' % (c_typename,): + return True + raise ValueError(answer) + + class Platform: def __init__(self): self.types = {} diff --git a/rpython/rtyper/tool/test/test_rfficache.py b/rpython/rtyper/tool/test/test_rfficache.py --- a/rpython/rtyper/tool/test/test_rfficache.py +++ b/rpython/rtyper/tool/test/test_rfficache.py @@ -15,3 +15,13 @@ assert hasattr(rffi, 'r_' + name) assert hasattr(rffi, name.upper()) +def test_signof_c_type(): + assert signof_c_type('signed char') == True + assert signof_c_type('unsigned char') == False + assert signof_c_type('long long') == True + assert signof_c_type('unsigned long long') == False + # + assert (sizeof_c_type('wchar_t'), signof_c_type('wchar_t')) in [ + (2, False), + (4, False), + (4, True)] From noreply at buildbot.pypy.org Tue Sep 29 11:34:20 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 11:34:20 +0200 (CEST) Subject: [pypy-commit] pypy default: Avoid warnings Message-ID: <20150929093420.110471C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79893:abbd1a53917f Date: 2015-09-29 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/abbd1a53917f/ Log: Avoid warnings diff --git a/rpython/rtyper/tool/rfficache.py b/rpython/rtyper/tool/rfficache.py --- a/rpython/rtyper/tool/rfficache.py +++ b/rpython/rtyper/tool/rfficache.py @@ -53,8 +53,9 @@ return result def signof_c_type(c_typename, **kwds): - question = 'printf("sign %s=%%d\\n", ((%s) -1) <= 0);' % (c_typename, - c_typename) + question = 'printf("sign %s=%%d\\n", ((%s) -1) <= (%s)0);' % (c_typename, + c_typename, + c_typename) answer = ask_gcc(question, **kwds).strip() if answer == 'sign %s=0' % (c_typename,): return False From noreply at buildbot.pypy.org Tue Sep 29 14:47:31 2015 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 29 Sep 2015 14:47:31 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: Fix: we must not call make_result_of_lastop here, because we'll always Message-ID: <20150929124731.227881C06AD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: share-guard-info Changeset: r79894:520532cf1510 Date: 2015-09-29 14:47 +0200 http://bitbucket.org/pypy/pypy/changeset/520532cf1510/ Log: Fix: we must not call make_result_of_lastop here, because we'll always resume at the start of the int_add_jump_if_ovf, not at the end. 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 @@ -238,7 +238,6 @@ def opimpl_%s(self, lbl, b1, b2, orgpc): self.metainterp.ovf_flag = False resbox = self.execute(rop.%s, b1, b2) - self.make_result_of_lastop(resbox) # same as execute_varargs() if not isinstance(resbox, Const): return self.handle_possible_overflow_error(lbl, orgpc, resbox) From noreply at buildbot.pypy.org Tue Sep 29 15:26:27 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 29 Sep 2015 15:26:27 +0200 (CEST) Subject: [pypy-commit] pypy share-guard-info: follow through enter_portal_frame, since it's ok nowadays Message-ID: <20150929132627.6AECC1C023F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: share-guard-info Changeset: r79895:50ba44e6ef57 Date: 2015-09-29 15:26 +0200 http://bitbucket.org/pypy/pypy/changeset/50ba44e6ef57/ Log: follow through enter_portal_frame, since it's ok nowadays 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 @@ -582,12 +582,7 @@ elif op.can_raise(): self.exception_might_have_happened = True if ((op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() or - op.is_ovf()) and - not self.is_call_pure_pure_canraise(op) and - not op.getopnum() == rop.ENTER_PORTAL_FRAME): - # we can't share across ENTER_PORTAL_FRAME because if we later - # change the decision of inlining into that portal frame, we - # won't follow the same path through blackhole + op.is_ovf()) and not self.is_call_pure_pure_canraise(op)): pass else: self._last_guard_op = None From noreply at buildbot.pypy.org Tue Sep 29 16:05:50 2015 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 29 Sep 2015 16:05:50 +0200 (CEST) Subject: [pypy-commit] cffi default: document usefulness of ffi.buffer() for reading a struct from a socket Message-ID: <20150929140550.7B2981C12AA@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r2280:adbff121e494 Date: 2015-09-29 17:06 +0300 http://bitbucket.org/cffi/cffi/changeset/adbff121e494/ Log: document usefulness of ffi.buffer() for reading a struct from a socket diff --git a/doc/source/using.rst b/doc/source/using.rst --- a/doc/source/using.rst +++ b/doc/source/using.rst @@ -615,11 +615,18 @@ 'cdata' must be a pointer or an array. If unspecified, the size of the buffer is either the size of what ``cdata`` points to, or the whole size of the array. Getting a buffer is useful because you can read from it -without an extra copy, or write into it to change the original value; -you can use for example ``file.write()`` and ``file.readinto()`` with -such a buffer (for files opened in binary mode). (Remember that like in -C, you can use ``array + index`` to get the pointer to the index'th item of -an array.) +without an extra copy, or write into it to change the original value. + +Here are a few examples of where buffer() would be useful: + +- use ``file.write()`` and ``file.readinto()`` with + such a buffer (for files opened in binary mode) + +- use ``ffi.buffer(mystruct[0])[:] = socket.recv(len(buffer))`` to read + into a struct over a socket, rewriting the contents of mystruct[0] + +Remember that like in C, you can use ``array + index`` to get the pointer +to the index'th item of an array. The returned object is not a built-in buffer nor memoryview object, because these objects' API changes too much across Python versions. From noreply at buildbot.pypy.org Tue Sep 29 16:07:34 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 29 Sep 2015 16:07:34 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: merged default Message-ID: <20150929140734.8D30C1C1330@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79896:fde3bd5b3b48 Date: 2015-09-29 16:07 +0200 http://bitbucket.org/pypy/pypy/changeset/fde3bd5b3b48/ Log: merged default diff too long, truncating to 2000 out of 6994 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -92,6 +92,8 @@ if sys.platform == "win32": module_suggests["cpyext"].append(("translation.shared", True)) + +# NOTE: this dictionary is not used any more module_import_dependencies = { # no _rawffi if importing rpython.rlib.clibffi raises ImportError # or CompilationError or py.test.skip.Exception @@ -108,6 +110,7 @@ } def get_module_validator(modname): + # NOTE: this function is not used any more if modname in module_import_dependencies: modlist = module_import_dependencies[modname] def validator(config): diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst --- a/pypy/doc/extending.rst +++ b/pypy/doc/extending.rst @@ -5,8 +5,8 @@ with any external library. Right now, there are the following possibilities of providing -third-party modules for the PyPy python interpreter (in order of -usefulness): +third-party modules for the PyPy python interpreter (in order, from most +directly useful to most messy to use with PyPy): * Write them in pure Python and use CFFI_. diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -67,7 +67,7 @@ The other commands of ``setup.py`` are available too, like ``build``. .. _PyPI: https://pypi.python.org/pypi -.. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv +.. _`use virtualenv (as documented here)`: install.html#installing-using-virtualenv Module xyz does not work in the sandboxed PyPy? diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -5,19 +5,8 @@ understanding what's pypy's JIT doing while running your program. There are three functions related to that coming from the ``pypyjit`` module: -.. function:: set_optimize_hook(callable) - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The callable will be called with the ``pypyjit.JitLoopInfo`` object. - Refer to it's documentation for details. - - Result value will be the resulting list of operations, or None - - -.. function:: set_compile_hook(callable) +.. function:: set_compile_hook(callable, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -28,6 +17,9 @@ inside the jit hook is itself jitted, it will get compiled, but the jit hook won't be called for that. + if operations=False, no list of operations will be available. Useful + if the hook is supposed to be very lighweight. + .. function:: set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing @@ -66,3 +58,25 @@ * ``loop_run_times`` - counters for number of times loops are run, only works when ``enable_debug`` is called. + +.. class:: JitLoopInfo + + A class containing information about the compiled loop. Usable attributes: + + * ``operations`` - list of operations, if requested + + * ``jitdriver_name`` - the name of jitdriver associated with this loop + + * ``greenkey`` - a key at which the loop got compiled (e.g. code position, + is_being_profiled, pycode tuple for python jitdriver) + + * ``loop_no`` - loop cardinal number + + * ``bridge_no`` - id of the fail descr + + * ``type`` - "entry bridge", "loop" or "bridge" + + * ``asmaddr`` - an address in raw memory where assembler resides + + * ``asmlen`` - length of raw memory with assembler associated + 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 @@ -22,6 +22,28 @@ .. branch: missing_openssl_include Fix for missing headers in OpenBSD, already applied in downstream ports +.. branch: gc-more-incremental +Remove a source of non-incremental-ness in the GC: now +external_malloc() no longer runs gc_step_until() any more. If there +is a currently-running major collection, we do only so many steps +before returning. This number of steps depends on the size of the +allocated object. It is controlled by tracking the general progress +of these major collection steps and the size of old objects that +keep adding up between them. + +.. branch: remember-tracing-counts +Reenable jithooks + +.. branch: detect_egd2 + +.. branch: shadowstack-no-move-2 +Issue #2141: fix a crash on Windows and OS/X and ARM when running +at least 20 threads. + +.. branch: numpy-ctypes + +Add support for ndarray.ctypes property. + .. branch: vecopt .. branch: vecopt-merge diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -341,8 +341,8 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy - #from pypy.module.pypyjit.hooks import pypy_hooks - return PyPyJitPolicy()#pypy_hooks) + from pypy.module.pypyjit.hooks import pypy_hooks + return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -5,6 +5,7 @@ from __future__ import with_statement import operator from __pypy__ import resizelist_hint, newlist_hint +from __pypy__ import specialized_zip_2_lists # ____________________________________________________________ @@ -217,11 +218,16 @@ in length to the length of the shortest argument sequence.""" l = len(sequences) if l == 2: + # A very fast path if the two sequences are lists + seq0 = sequences[0] + seq1 = sequences[1] + try: + return specialized_zip_2_lists(seq0, seq1) + except TypeError: + pass # This is functionally the same as the code below, but more # efficient because it unrolls the loops over 'sequences'. # Only for two arguments, which is the most common case. - seq0 = sequences[0] - seq1 = sequences[1] iter0 = iter(seq0) iter1 = iter(seq1) hint = min(100000000, # max 100M diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -83,6 +83,7 @@ 'newdict' : 'interp_dict.newdict', 'reversed_dict' : 'interp_dict.reversed_dict', 'strategy' : 'interp_magic.strategy', # dict,set,list + 'specialized_zip_2_lists' : 'interp_magic.specialized_zip_2_lists', 'set_debug' : 'interp_magic.set_debug', 'locals_to_fast' : 'interp_magic.locals_to_fast', 'save_module_content_for_future_reload': diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -147,3 +147,7 @@ @unwrap_spec(w_module=MixedModule) def save_module_content_for_future_reload(space, w_module): w_module.save_module_content_for_future_reload() + +def specialized_zip_2_lists(space, w_list1, w_list2): + from pypy.objspace.std.specialisedtupleobject import specialized_zip_2_lists + return specialized_zip_2_lists(space, w_list1, w_list2) diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -7,6 +7,7 @@ from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rfficache from pypy.interpreter.error import oefmt from pypy.module._cffi_backend import cdataobj, misc @@ -125,12 +126,25 @@ cdata[0] = value +# XXX explicitly use an integer type instead of lltype.UniChar here, +# because for now the latter is defined as unsigned by RPython (even +# though it may be signed when 'wchar_t' is written to C). +WCHAR_INT = {(2, False): rffi.USHORT, + (4, False): rffi.UINT, + (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar), + rfficache.signof_c_type('wchar_t')] +WCHAR_INTP = rffi.CArrayPtr(WCHAR_INT) + class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar): _attrs_ = [] + if rffi.r_wchar_t.SIGN: + def write_raw_integer_data(self, w_cdata, value): + w_cdata.write_raw_signed_data(value) + def cast_to_int(self, cdata): - unichardata = rffi.cast(rffi.CWCHARP, cdata) - return self.space.wrap(ord(unichardata[0])) + unichardata = rffi.cast(WCHAR_INTP, cdata) + return self.space.wrap(unichardata[0]) def convert_to_object(self, cdata): unichardata = rffi.cast(rffi.CWCHARP, cdata) diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -241,20 +241,26 @@ res = libssl_RAND_status() return space.wrap(res) - @unwrap_spec(path=str) - def RAND_egd(space, path): - """RAND_egd(path) -> bytes + if HAVE_OPENSSL_RAND_EGD: + @unwrap_spec(path=str) + def RAND_egd(space, path): + """RAND_egd(path) -> bytes - Queries the entropy gather daemon (EGD) on socket path. Returns number - of bytes read. Raises socket.sslerror if connection to EGD fails or - if it does provide enough data to seed PRNG.""" - with rffi.scoped_str2charp(path) as socket_path: - bytes = libssl_RAND_egd(socket_path) - if bytes == -1: - raise ssl_error(space, - "EGD connection failed or EGD did not return " - "enough data to seed the PRNG") - return space.wrap(bytes) + Queries the entropy gather daemon (EGD) on socket path. Returns number + of bytes read. Raises socket.sslerror if connection to EGD fails or + if it does provide enough data to seed PRNG.""" + with rffi.scoped_str2charp(path) as socket_path: + bytes = libssl_RAND_egd(socket_path) + if bytes == -1: + raise ssl_error(space, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG") + return space.wrap(bytes) + else: + # Dummy func for platforms missing RAND_egd(). Most likely LibreSSL. + @unwrap_spec(path=str) + def RAND_egd(space, path): + raise ssl_error(space, "RAND_egd unavailable") class _SSLSocket(W_Root): diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -36,7 +36,8 @@ assert isinstance(_ssl.OPENSSL_VERSION_INFO, tuple) assert len(_ssl.OPENSSL_VERSION_INFO) == 5 assert isinstance(_ssl.OPENSSL_VERSION, str) - assert 'openssl' in _ssl.OPENSSL_VERSION.lower() + lower_version = _ssl.OPENSSL_VERSION.lower() + assert 'openssl' in lower_version or "libressl" in lower_version assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int) @@ -69,8 +70,9 @@ def test_sslwrap(self): import _ssl, _socket, sys, gc - if sys.platform == 'darwin' or 'freebsd' in sys.platform: - skip("hangs indefinitely on OSX & FreeBSD (also on CPython)") + if sys.platform == 'darwin' or 'freebsd' in sys.platform or \ + 'openbsd' in sys.platform: + skip("hangs indefinitely on OSX & BSD (also on CPython)") s = _socket.socket() if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py --- a/pypy/module/_vmprof/test/test__vmprof.py +++ b/pypy/module/_vmprof/test/test__vmprof.py @@ -34,6 +34,7 @@ i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) i += 2 * WORD + size * struct.calcsize("P") + i += WORD # thread id elif s[i] == '\x02': i += 1 _, size = struct.unpack("ll", s[i:i + 2 * WORD]) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -844,6 +844,18 @@ b.byteswap() assert a != b + def test_unicode_ord_positive(self): + import sys + if sys.maxunicode == 0xffff: + skip("test for 32-bit unicodes") + a = self.array('u', '\xff\xff\xff\xff') + assert len(a) == 1 + assert repr(a[0]) == "u'\Uffffffff'" + if sys.maxint == 2147483647: + assert ord(a[0]) == -1 + else: + assert ord(a[0]) == 4294967295 + def test_weakref(self): import weakref a = self.array('c', 'Hi!') diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from rpython.rlib import jit class W_Count(W_Root): @@ -322,6 +323,11 @@ """) +islice_ignore_items_driver = jit.JitDriver(name='islice_ignore_items', + greens=['tp'], + reds=['num', 'w_islice', + 'w_iterator']) + class W_ISlice(W_Root): def __init__(self, space, w_iterable, w_startstop, args_w): self.iterable = space.iter(w_iterable) @@ -407,11 +413,18 @@ raise def _ignore_items(self, num): - if self.iterable is None: + w_iterator = self.iterable + if w_iterator is None: raise OperationError(self.space.w_StopIteration, self.space.w_None) + + tp = self.space.type(w_iterator) while True: + islice_ignore_items_driver.jit_merge_point(tp=tp, + num=num, + w_islice=self, + w_iterator=w_iterator) try: - self.space.next(self.iterable) + self.space.next(w_iterator) except OperationError as e: if e.match(self.space, self.space.w_StopIteration): self.iterable = None diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -1085,3 +1085,18 @@ assert list(itertools.islice(c2, 3)) == expected c3 = pickle.loads(pickle.dumps(c)) assert list(itertools.islice(c3, 3)) == expected + + def test_islice_attack(self): + import itertools + class Iterator(object): + first = True + def __iter__(self): + return self + def next(self): + if self.first: + self.first = False + list(islice) + return 52 + myiter = Iterator() + islice = itertools.islice(myiter, 5, 8) + raises(StopIteration, islice.next) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -9,6 +9,7 @@ 'ndarray': 'ndarray.W_NDimArray', 'dtype': 'descriptor.W_Dtype', 'flatiter': 'flatiter.W_FlatIterator', + 'flagsobj': 'flagsobj.W_FlagsObject', '_reconstruct' : 'ndarray._reconstruct', 'scalar' : 'ctors.build_scalar', diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,6 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype +from rpython.rlib.rarithmetic import ovfcheck from pypy.module.micronumpy import support from pypy.module.micronumpy import constants as NPY @@ -44,9 +45,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(shape) * dtype.elsize + ovfcheck(support.product_check(shape) * dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(shape, dtype.base, order) impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides, zero=zero) @@ -68,9 +69,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - totalsize = support.product(shape) * isize + totalsize = ovfcheck(support.product_check(shape) * isize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if storage_bytes > 0 : if totalsize > storage_bytes: raise OperationError(space.w_TypeError, space.wrap( @@ -116,12 +117,14 @@ return W_NDimArray(impl) @staticmethod - def new_slice(space, offset, strides, backstrides, shape, parent, orig_arr, dtype=None): + def new_slice(space, offset, strides, backstrides, shape, parent, w_arr, dtype=None): from pypy.module.micronumpy import concrete - + w_base = w_arr + if w_arr.implementation.base() is not None: + w_base = w_arr.implementation.base() impl = concrete.SliceArray(offset, strides, backstrides, shape, parent, - orig_arr, dtype) - return wrap_impl(space, space.type(orig_arr), orig_arr, impl) + w_base, dtype) + return wrap_impl(space, space.type(w_arr), w_arr, impl) @staticmethod def new_scalar(space, dtype, w_val=None): diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -147,7 +147,7 @@ def get_flags(self): return (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS | - NPY.ARRAY_WRITEABLE | NPY.ARRAY_OWNDATA) + NPY.ARRAY_ALIGNED | NPY.ARRAY_OWNDATA) def item(self, space): return self.get_dtype(space).itemtype.to_builtin_type(space, self) diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -1,5 +1,7 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit, rgc +from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.buffer import Buffer from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \ @@ -16,6 +18,19 @@ is_f_contiguous) from rpython.rlib.objectmodel import keepalive_until_here +TimSort = make_timsort_class() +class StrideSort(TimSort): + ''' + argsort (return the indices to sort) a list of strides + ''' + def __init__(self, rangelist, strides): + self.strides = strides + TimSort.__init__(self, rangelist) + + def lt(self, a, b): + return self.strides[a] < self.strides[b] + + class BaseConcreteArray(object): _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]', 'strides[*]', 'backstrides[*]', 'order', 'gcstruct', @@ -353,12 +368,15 @@ elif order != self.order: t_strides, backstrides = calc_strides(shape, dtype, order) else: - mins = strides[0] + indx_array = range(len(strides)) + list_sorter = StrideSort(indx_array, strides) + list_sorter.sort() t_elsize = dtype.elsize - for s in strides: - if s < mins: - mins = s - t_strides = [s * t_elsize / mins for s in strides] + t_strides = strides[:] + base = dtype.elsize + for i in indx_array: + t_strides[i] = base + base *= shape[i] backstrides = calc_backstrides(t_strides, shape) impl = ConcreteArray(shape, dtype, order, t_strides, backstrides) loop.setslice(space, impl.get_shape(), impl, self) @@ -409,6 +427,7 @@ make_sure_not_resized(strides) make_sure_not_resized(backstrides) self.shape = shape + # already tested for overflow in from_shape_and_storage self.size = support.product(shape) * dtype.elsize self.order = order self.dtype = dtype @@ -428,9 +447,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") strides, backstrides = calc_strides(new_shape, self.dtype, self.order) return SliceArray(self.start, strides, backstrides, new_shape, self, @@ -457,8 +476,11 @@ storage=lltype.nullptr(RAW_STORAGE), zero=True): gcstruct = V_OBJECTSTORE flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE - length = support.product(shape) - self.size = length * dtype.elsize + try: + length = support.product_check(shape) + self.size = ovfcheck(length * dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") if storage == lltype.nullptr(RAW_STORAGE): if dtype.num == NPY.OBJECT: storage = dtype.itemtype.malloc(length * dtype.elsize, zero=True) @@ -542,7 +564,10 @@ self.gcstruct = parent.gcstruct self.order = parent.order self.dtype = dtype - self.size = support.product(shape) * self.dtype.elsize + try: + self.size = ovfcheck(support.product_check(shape) * self.dtype.elsize) + except OverflowError: + raise oefmt(dtype.itemtype.space.w_ValueError, "array is too big.") self.start = start self.orig_arr = orig_arr flags = parent.flags & NPY.ARRAY_ALIGNED @@ -564,9 +589,9 @@ raise oefmt(space.w_ValueError, "sequence too large; must be smaller than %d", NPY.MAXDIMS) try: - support.product(new_shape) * self.dtype.elsize + ovfcheck(support.product_check(new_shape) * self.dtype.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") if len(self.get_shape()) < 2 or self.size == 0: # TODO: this code could be refactored into calc_strides # but then calc_strides would have to accept a stepping factor diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -133,7 +133,9 @@ return w_arr else: imp = w_object.implementation - w_base = imp.base() or w_object + w_base = w_object + if imp.base() is not None: + w_base = imp.base() with imp as storage: sz = support.product(w_object.get_shape()) * dtype.elsize return W_NDimArray.from_shape_and_storage(space, @@ -153,7 +155,7 @@ dtype = descriptor.variable_dtype(space, dtype.char + '1') w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) - if support.product(shape) == 1: + if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: loop.assign(space, w_arr, elems_w) @@ -213,10 +215,9 @@ raise OperationError(space.w_ValueError, space.wrap( "negative dimensions are not allowed")) try: - support.product(shape) + support.product_check(shape) except OverflowError: - raise OperationError(space.w_ValueError, space.wrap( - "array is too big.")) + raise oefmt(space.w_ValueError, "array is too big.") return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py --- a/pypy/module/micronumpy/flagsobj.py +++ b/pypy/module/micronumpy/flagsobj.py @@ -57,6 +57,9 @@ self.flags & NPY.ARRAY_F_CONTIGUOUS or self.flags & NPY.ARRAY_C_CONTIGUOUS )) + def descr_get_num(self, space): + return space.wrap(self.flags) + def descr_getitem(self, space, w_item): key = space.str_w(w_item) if key == "C" or key == "CONTIGUOUS" or key == "C_CONTIGUOUS": @@ -122,4 +125,5 @@ aligned = GetSetProperty(W_FlagsObject.descr_get_aligned), fnc = GetSetProperty(W_FlagsObject.descr_get_fnc), forc = GetSetProperty(W_FlagsObject.descr_get_forc), + num = GetSetProperty(W_FlagsObject.descr_get_num), ) diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -6,6 +6,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from rpython.rlib.rawstorage import RAW_STORAGE_PTR +from rpython.rlib.rarithmetic import ovfcheck from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy import descriptor, ufuncs, boxes, arrayops, loop, \ @@ -611,6 +612,7 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + # sz cannot overflow since self is valid sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, @@ -745,8 +747,12 @@ return out def descr_get_ctypes(self, space): - raise OperationError(space.w_NotImplementedError, space.wrap( - "ctypes not implemented yet")) + w_result = space.appexec([self], """(arr): + from numpy.core import _internal + p_data = arr.__array_interface__['data'][0] + return _internal._ctypes(arr, p_data) + """) + return w_result def buffer_w(self, space, flags): return self.implementation.get_buffer(space, True) @@ -1405,9 +1411,9 @@ return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) try: - totalsize = support.product(shape) * dtype.base.elsize + totalsize = ovfcheck(support.product_check(shape) * dtype.base.elsize) except OverflowError as e: - raise oefmt(space.w_ValueError, "array is too big") + raise oefmt(space.w_ValueError, "array is too big.") impl = ConcreteArray(shape, dtype.base, order, strides, backstrides) w_ret = space.allocate_instance(W_NDimArray, w_subtype) W_NDimArray.__init__(w_ret, impl) diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -32,10 +32,16 @@ def product(s): i = 1 for x in s: + i *= x + return i + + at jit.unroll_safe +def product_check(s): + i = 1 + for x in s: i = ovfcheck(i * x) return i - def check_and_adjust_index(space, index, size, axis): if index < -size or index >= size: if axis >= 0: diff --git a/pypy/module/micronumpy/test/test_flagsobj.py b/pypy/module/micronumpy/test/test_flagsobj.py --- a/pypy/module/micronumpy/test/test_flagsobj.py +++ b/pypy/module/micronumpy/test/test_flagsobj.py @@ -30,6 +30,7 @@ assert a.flags.forc == True assert a.flags['FNC'] == False assert a.flags['FORC'] == True + assert a.flags.num == 1287 raises(KeyError, "a.flags['blah']") raises(KeyError, "a.flags['C_CONTIGUOUS'] = False") raises((TypeError, AttributeError), "a.flags.c_contiguous = False") @@ -38,6 +39,7 @@ import numpy as np a = np.int32(2) assert a.flags.c_contiguous == True + assert a.flags.num == 263 def test_compare(self): import numpy as np diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -270,7 +270,7 @@ exc = raises(ValueError, ndarray, [1,2,256]*10000) assert exc.value[0] == 'sequence too large; must be smaller than 32' exc = raises(ValueError, ndarray, [1,2,256]*10) - assert exc.value[0] == 'array is too big' + assert exc.value[0] == 'array is too big.' def test_ndmin(self): from numpy import array @@ -2218,7 +2218,7 @@ assert _weakref.ref(a) def test_astype(self): - from numpy import array, arange + from numpy import array, arange, empty b = array(1).astype(float) assert b == 1 assert b.dtype == float @@ -2273,14 +2273,36 @@ b = a.astype('f4', order='C', copy=False) assert a is b + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + c = b[:, :2, :] + d = c.swapaxes(1, -1) + e = d.astype('complex128') + assert e.shape == (3, 3, 2) + assert e.strides == (96, 16, 48) + assert (e.real == d).all() + def test_base(self): - from numpy import array + from numpy import array, empty assert array(1).base is None assert array([1, 2]).base is None a = array([1, 2, 3, 4]) b = a[::2] assert b.base is a + a = empty([3, 3, 3, 3], 'uint8') + a[:] = 0 + b = a[2] + assert b.base.base is None + c = b[:, :2, :] + d = c.swapaxes(1, -1) + assert c.base.base is None + assert d.base.base is None + assert d.shape == (3, 3, 2) + assert d.__array_interface__['data'][0] == \ + a.__array_interface__['data'][0] + a.strides[0] * 2 + def test_byteswap(self): from numpy import array @@ -2497,10 +2519,10 @@ assert b.shape == b[...].shape assert (b == b[...]).all() - a = np.arange(6).reshape(2, 3) + a = np.arange(6) if '__pypy__' in sys.builtin_module_names: raises(ValueError, "a[..., ...]") - b = a [..., 0] + b = a.reshape(2, 3)[..., 0] assert (b == [0, 3]).all() assert b.base is a diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -1006,7 +1006,6 @@ assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): # reshape - sz = product(curarg.get_shape()) * curarg.get_dtype().elsize with curarg.implementation as storage: inargs[i] = W_NDimArray.from_shape_and_storage( diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -8,16 +8,18 @@ 'set_param': 'interp_jit.set_param', 'residual_call': 'interp_jit.residual_call', 'not_from_assembler': 'interp_jit.W_NotFromAssembler', - #'set_compile_hook': 'interp_resop.set_compile_hook', - #'set_optimize_hook': 'interp_resop.set_optimize_hook', - #'set_abort_hook': 'interp_resop.set_abort_hook', - #'get_stats_snapshot': 'interp_resop.get_stats_snapshot', - #'enable_debug': 'interp_resop.enable_debug', - #'disable_debug': 'interp_resop.disable_debug', - #'ResOperation': 'interp_resop.WrappedOp', - #'DebugMergePoint': 'interp_resop.DebugMergePoint', - #'JitLoopInfo': 'interp_resop.W_JitLoopInfo', - #'Box': 'interp_resop.WrappedBox', + 'get_jitcell_at_key': 'interp_jit.get_jitcell_at_key', + 'dont_trace_here': 'interp_jit.dont_trace_here', + 'trace_next_iteration': 'interp_jit.trace_next_iteration', + 'trace_next_iteration_hash': 'interp_jit.trace_next_iteration_hash', + 'set_compile_hook': 'interp_resop.set_compile_hook', + 'set_abort_hook': 'interp_resop.set_abort_hook', + 'get_stats_snapshot': 'interp_resop.get_stats_snapshot', + 'enable_debug': 'interp_resop.enable_debug', + 'disable_debug': 'interp_resop.disable_debug', + 'ResOperation': 'interp_resop.WrappedOp', + 'DebugMergePoint': 'interp_resop.DebugMergePoint', + 'JitLoopInfo': 'interp_resop.W_JitLoopInfo', 'PARAMETER_DOCS': 'space.wrap(rpython.rlib.jit.PARAMETER_DOCS)', } diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py --- a/pypy/module/pypyjit/hooks.py +++ b/pypy/module/pypyjit/hooks.py @@ -35,10 +35,10 @@ self._compile_hook(debug_info, is_bridge=True) def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) + pass def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) + pass def _compile_hook(self, debug_info, is_bridge): space = self.space @@ -46,7 +46,8 @@ if cache.in_recursion: return if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge, + cache.compile_hook_with_ops) cache.in_recursion = True try: try: @@ -57,33 +58,4 @@ finally: cache.in_recursion = False - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -5,11 +5,14 @@ from rpython.rlib.rarithmetic import r_uint, intmask from rpython.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside -from rpython.rlib import jit -from rpython.rlib.jit import current_trace_length, unroll_parameters +from rpython.rlib import jit, jit_hooks +from rpython.rlib.jit import current_trace_length, unroll_parameters,\ + JitHookInterface +from rpython.rtyper.annlowlevel import cast_instance_to_gcref import pypy.interpreter.pyopcode # for side-effects from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.pycode import CO_GENERATOR, PyCode +from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pyopcode import ExitFrame, Yield from pypy.interpreter.baseobjspace import W_Root @@ -188,3 +191,100 @@ __call__ = interp2app(W_NotFromAssembler.descr_call), ) W_NotFromAssembler.typedef.acceptable_as_base_class = False + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def get_jitcell_at_key(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + return space.wrap(bool(jit_hooks.get_jitcell_at_key( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode))) + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def dont_trace_here(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.dont_trace_here( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(next_instr=int, is_being_profiled=bool, w_pycode=PyCode) + at dont_look_inside +def trace_next_iteration(space, next_instr, is_being_profiled, w_pycode): + ll_pycode = cast_instance_to_gcref(w_pycode) + jit_hooks.trace_next_iteration( + 'pypyjit', r_uint(next_instr), int(is_being_profiled), ll_pycode) + return space.w_None + + at unwrap_spec(hash=r_uint) + at dont_look_inside +def trace_next_iteration_hash(space, hash): + jit_hooks.trace_next_iteration_hash('pypyjit', hash) + return space.w_None + +# class Cache(object): +# in_recursion = False + +# def __init__(self, space): +# self.w_compile_bridge = space.w_None +# self.w_compile_loop = space.w_None + +# def set_compile_bridge(space, w_hook): +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_bridge = w_hook + +# def set_compile_loop(space, w_hook): +# from rpython.rlib.nonconst import NonConstant + +# cache = space.fromcache(Cache) +# assert w_hook is not None +# cache.w_compile_loop = w_hook +# cache.in_recursion = NonConstant(False) + +# class PyPyJitHookInterface(JitHookInterface): +# def after_compile(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# l_w = [] +# if not space.is_true(cache.w_compile_loop): +# return +# for i, op in enumerate(debug_info.operations): +# if op.is_guard(): +# w_t = space.newtuple([space.wrap(i), space.wrap(op.getopnum()), space.wrap(op.getdescr().get_jitcounter_hash())]) +# l_w.append(w_t) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_loop, space.newlist(l_w)) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def after_compile_bridge(self, debug_info): +# space = self.space +# cache = space.fromcache(Cache) +# if cache.in_recursion: +# return +# if not space.is_true(cache.w_compile_bridge): +# return +# w_hash = space.wrap(debug_info.fail_descr.get_jitcounter_hash()) +# try: +# cache.in_recursion = True +# try: +# space.call_function(cache.w_compile_bridge, w_hash) +# except OperationError, e: +# e.write_unraisable(space, "jit hook ", cache.w_compile_bridge) +# finally: +# cache.in_recursion = False + +# def before_compile(self, debug_info): +# pass + +# def before_compile_bridge(self, debug_info): +# pass + +# pypy_hooks = PyPyJitHookInterface() + diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -22,7 +22,6 @@ def __init__(self, space): self.w_compile_hook = space.w_None self.w_abort_hook = space.w_None - self.w_optimize_hook = space.w_None def getno(self): self.no += 1 @@ -43,8 +42,9 @@ else: return space.wrap(greenkey_repr) -def set_compile_hook(space, w_hook): - """ set_compile_hook(hook) + at unwrap_spec(operations=bool) +def set_compile_hook(space, w_hook, operations=True): + """ set_compile_hook(hook, operations=True) Set a compiling hook that will be called each time a loop is compiled. @@ -58,25 +58,9 @@ cache = space.fromcache(Cache) assert w_hook is not None cache.w_compile_hook = w_hook + cache.compile_hook_with_ops = operations cache.in_recursion = NonConstant(False) -def set_optimize_hook(space, w_hook): - """ set_optimize_hook(hook) - - Set a compiling hook that will be called each time a loop is optimized, - but before assembler compilation. This allows adding additional - optimizations on Python level. - - The hook will be called with the pypyjit.JitLoopInfo object. Refer to it's - docstring for details. - - Result value will be the resulting list of operations, or None - """ - cache = space.fromcache(Cache) - cache.w_optimize_hook = w_hook - cache.in_recursion = NonConstant(False) - - def set_abort_hook(space, w_hook): """ set_abort_hook(hook) @@ -96,6 +80,9 @@ cache.in_recursion = NonConstant(False) def wrap_oplist(space, logops, operations, ops_offset=None): + # this function is called from the JIT + from rpython.jit.metainterp.resoperation import rop + l_w = [] jitdrivers_sd = logops.metainterp_sd.jitdrivers_sd for op in operations: @@ -103,117 +90,58 @@ ofs = -1 else: ofs = ops_offset.get(op, 0) - if op.opnum == rop.DEBUG_MERGE_POINT: + num = op.getopnum() + name = op.getopname() + if num == rop.DEBUG_MERGE_POINT: jd_sd = jitdrivers_sd[op.getarg(0).getint()] greenkey = op.getarglist()[3:] repr = jd_sd.warmstate.get_location_str(greenkey) w_greenkey = wrap_greenkey(space, jd_sd.jitdriver, greenkey, repr) - l_w.append(DebugMergePoint(space, jit_hooks._cast_to_gcref(op), + l_w.append(DebugMergePoint(space, name, logops.repr_of_resop(op), jd_sd.jitdriver.name, op.getarg(1).getint(), op.getarg(2).getint(), w_greenkey)) else: - l_w.append(WrappedOp(jit_hooks._cast_to_gcref(op), ofs, - logops.repr_of_resop(op))) + l_w.append(WrappedOp(name, ofs, logops.repr_of_resop(op))) return l_w + at unwrap_spec(offset=int, repr=str, name=str) +def descr_new_resop(space, w_tp, name, offset=-1, repr=''): + return WrappedOp(name, offset, repr) -class WrappedBox(W_Root): - """ A class representing a single box - """ - def __init__(self, llbox): - self.llbox = llbox - - def descr_getint(self, space): - if not jit_hooks.box_isint(self.llbox): - raise OperationError(space.w_NotImplementedError, - space.wrap("Box has no int value")) - return space.wrap(jit_hooks.box_getint(self.llbox)) - - at unwrap_spec(no=int) -def descr_new_box(space, w_tp, no): - return WrappedBox(jit_hooks.boxint_new(no)) - -WrappedBox.typedef = TypeDef( - 'Box', - __new__ = interp2app(descr_new_box), - getint = interp2app(WrappedBox.descr_getint), -) - - at unwrap_spec(num=int, offset=int, repr=str, w_res=W_Root) -def descr_new_resop(space, w_tp, num, w_args, w_res, offset=-1, - repr=''): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - if space.is_none(w_res): - llres = jit_hooks.emptyval() - else: - if not isinstance(w_res, WrappedBox): - raise OperationError(space.w_TypeError, space.wrap( - "expected box type, got %s" % space.type(w_res))) - llres = w_res.llbox - return WrappedOp(jit_hooks.resop_new(num, args, llres), offset, repr) - - at unwrap_spec(repr=str, jd_name=str, call_depth=int, call_id=int) -def descr_new_dmp(space, w_tp, w_args, repr, jd_name, call_depth, call_id, + at unwrap_spec(repr=str, name=str, jd_name=str, call_depth=int, call_id=int) +def descr_new_dmp(space, w_tp, name, repr, jd_name, call_depth, call_id, w_greenkey): - args = [space.interp_w(WrappedBox, w_arg).llbox for w_arg in - space.listview(w_args)] - num = rop.DEBUG_MERGE_POINT - return DebugMergePoint(space, - jit_hooks.resop_new(num, args, jit_hooks.emptyval()), + return DebugMergePoint(space, name, repr, jd_name, call_depth, call_id, w_greenkey) class WrappedOp(W_Root): """ A class representing a single ResOperation, wrapped nicely """ - def __init__(self, op, offset, repr_of_resop): - self.op = op + def __init__(self, name, offset, repr_of_resop): self.offset = offset + self.name = name self.repr_of_resop = repr_of_resop def descr_repr(self, space): return space.wrap(self.repr_of_resop) - def descr_num(self, space): - return space.wrap(jit_hooks.resop_getopnum(self.op)) - def descr_name(self, space): - return space.wrap(hlstr(jit_hooks.resop_getopname(self.op))) - - @unwrap_spec(no=int) - def descr_getarg(self, space, no): - try: - box = jit_hooks.resop_getarg(self.op, no) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("Index out of range")) - return WrappedBox(box) - - @unwrap_spec(no=int, w_box=WrappedBox) - def descr_setarg(self, space, no, w_box): - jit_hooks.resop_setarg(self.op, no, w_box.llbox) - - def descr_getresult(self, space): - return WrappedBox(jit_hooks.resop_getresult(self.op)) - - def descr_setresult(self, space, w_box): - box = space.interp_w(WrappedBox, w_box) - jit_hooks.resop_setresult(self.op, box.llbox) + return space.wrap(self.name) class DebugMergePoint(WrappedOp): """ A class representing Debug Merge Point - the entry point to a jitted loop. """ - def __init__(self, space, op, repr_of_resop, jd_name, call_depth, call_id, - w_greenkey): + def __init__(self, space, name, repr_of_resop, jd_name, call_depth, + call_id, w_greenkey): - WrappedOp.__init__(self, op, -1, repr_of_resop) + WrappedOp.__init__(self, name, -1, repr_of_resop) self.jd_name = jd_name self.call_depth = call_depth self.call_id = call_id @@ -237,12 +165,7 @@ __doc__ = WrappedOp.__doc__, __new__ = interp2app(descr_new_resop), __repr__ = interp2app(WrappedOp.descr_repr), - num = GetSetProperty(WrappedOp.descr_num), name = GetSetProperty(WrappedOp.descr_name), - getarg = interp2app(WrappedOp.descr_getarg), - setarg = interp2app(WrappedOp.descr_setarg), - result = GetSetProperty(WrappedOp.descr_getresult, - WrappedOp.descr_setresult), offset = interp_attrproperty("offset", cls=WrappedOp), ) WrappedOp.typedef.acceptable_as_base_class = False @@ -278,14 +201,18 @@ asmaddr = 0 asmlen = 0 - def __init__(self, space, debug_info, is_bridge=False): - logops = debug_info.logger._make_log_operations() - if debug_info.asminfo is not None: - ofs = debug_info.asminfo.ops_offset + def __init__(self, space, debug_info, is_bridge=False, wrap_ops=True): + if wrap_ops: + memo = {} + logops = debug_info.logger._make_log_operations(memo) + if debug_info.asminfo is not None: + ofs = debug_info.asminfo.ops_offset + else: + ofs = {} + ops = debug_info.operations + self.w_ops = space.newlist(wrap_oplist(space, logops, ops, ofs)) else: - ofs = {} - self.w_ops = space.newlist( - wrap_oplist(space, logops, debug_info.operations, ofs)) + self.w_ops = space.w_None self.jd_name = debug_info.get_jitdriver().name self.type = debug_info.type diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -136,7 +136,6 @@ assert dmp.call_id == 0 assert dmp.offset == -1 assert int_add.name == 'int_add' - assert int_add.num == self.int_add_num assert int_add.offset == 0 self.on_compile_bridge() expected = ('>) + p33 = getinteriorfield_gc_r(p31, i26, descr=>) ... """) @@ -64,9 +64,9 @@ i8 = int_lt(i5, i7) guard_true(i8, descr=...) guard_not_invalidated(descr=...) - p10 = call(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) + p10 = call_r(ConstClass(ll_str__IntegerR_SignedConst_Signed), i5, descr=) guard_no_exception(descr=...) - i12 = call(ConstClass(ll_strhash), p10, descr=) + i12 = call_i(ConstClass(ll_strhash), p10, descr=) p13 = new(descr=...) p15 = new_array_clear(16, descr=) {{{ @@ -74,25 +74,25 @@ setfield_gc(p13, p15, descr=) setfield_gc(p13, ConstPtr(0), descr=) }}} - i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) + i17 = call_i(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 1, descr=) {{{ setfield_gc(p13, 0, descr=) setfield_gc(p13, 0, descr=) setfield_gc(p13, 32, descr=) }}} guard_no_exception(descr=...) - p20 = new_with_vtable(ConstClass(W_IntObject)) - call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) + p20 = new_with_vtable(descr=...) + call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=) setfield_gc(p20, i5, descr=) guard_no_exception(descr=...) - i23 = call(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) + i23 = call_i(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=) guard_no_exception(descr=...) i27 = int_lt(i23, 0) guard_false(i27, descr=...) - p28 = getfield_gc(p13, descr=) - p29 = getinteriorfield_gc(p28, i23, descr=>) + p28 = getfield_gc_r(p13, descr=) + p29 = getinteriorfield_gc_r(p28, i23, descr=>) guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...) - i31 = getfield_gc_pure(p29, descr=) + i31 = getfield_gc_pure_i(p29, descr=) i32 = int_sub_ovf(i31, i5) guard_no_overflow(descr=...) i34 = int_add_ovf(i32, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py --- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py +++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py @@ -31,7 +31,7 @@ # but all calls can be special-cased by the backend if # supported. On 64-bit there is only the two calls to # read_timestamp. - r = re.compile(r" call[(]ConstClass[(](.+?)[)]") + r = re.compile(r" call_\w[(]ConstClass[(](.+?)[)]") calls = r.findall(repr(loop.ops_by_id(method))) if sys.maxint == 2147483647: assert len(calls) == 6 diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -414,11 +414,7 @@ guard_not_invalidated(descr=...) p163 = force_token() p164 = force_token() - p165 = getarrayitem_gc(p67, 0, descr=) - guard_value(p165, ConstPtr(ptr70), descr=...) - p166 = getfield_gc(p165, descr=) - guard_value(p166, ConstPtr(ptr72), descr=...) - p167 = call(ConstClass(_ll_0_alloc_with_del___), descr=) + p167 = call_r(ConstClass(_ll_0_alloc_with_del___), descr=) guard_no_exception(descr=...) i112 = int_signext(i160, 2) setfield_gc(p167, ConstPtr(ptr85), descr=) @@ -426,11 +422,11 @@ i114 = int_ne(i160, i112) guard_false(i114, descr=...) --TICK-- - i119 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) + i123 = arraylen_gc(p67, descr=) + i119 = call_i(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=) raw_store(i119, 0, i160, descr=) raw_store(i119, 2, i160, descr=) raw_store(i119, 4, i160, descr=) setfield_gc(p167, i119, descr=) - i123 = arraylen_gc(p67, descr=) jump(..., descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_generators.py b/pypy/module/pypyjit/test_pypy_c/test_generators.py --- a/pypy/module/pypyjit/test_pypy_c/test_generators.py +++ b/pypy/module/pypyjit/test_pypy_c/test_generators.py @@ -21,10 +21,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + ifoo = arraylen_gc(p8, descr=) setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ @@ -50,10 +50,10 @@ assert loop.match_by_id("generator", """ cond_call(..., descr=...) i16 = force_token() - p45 = new_with_vtable(ConstClass(W_IntObject)) + p45 = new_with_vtable(descr=<.*>) + i47 = arraylen_gc(p8, descr=) # Should be removed by backend setfield_gc(p45, i29, descr=) setarrayitem_gc(p8, 0, p45, descr=) - i47 = arraylen_gc(p8, descr=) # Should be removed by backend jump(..., descr=...) """) assert loop.match_by_id("subtract", """ diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py --- a/pypy/module/pypyjit/test_pypy_c/test_globals.py +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -16,9 +16,9 @@ assert log.result == 500 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id("loadglobal", """ - p12 = getfield_gc(p10, descr=) + p12 = getfield_gc_r(p10, descr=) guard_value(p12, ConstPtr(ptr13), descr=...) guard_not_invalidated(descr=...) - p19 = getfield_gc(ConstPtr(p17), descr=) + p19 = getfield_gc_r(ConstPtr(p17), descr=) guard_value(p19, ConstPtr(ptr20), descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -106,7 +106,7 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc'] + 'getfield_gc_i'] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] # @@ -124,7 +124,7 @@ setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) - jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, descr=...) + jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, p100, descr=...) """) def test_mutate_class(self): @@ -154,8 +154,8 @@ entry_bridge, = log.loops_by_filename(self.filepath, is_entry_bridge=True) ops = entry_bridge.ops_by_id('mutate', opcode='LOAD_ATTR') assert log.opnames(ops) == ['guard_value', 'guard_not_invalidated', - 'getfield_gc', 'guard_nonnull_class', - 'getfield_gc', 'guard_value', # type check on the attribute + 'getfield_gc_r', 'guard_nonnull_class', + 'getfield_gc_r', 'guard_value', # type check on the attribute ] # the STORE_ATTR is folded away assert list(entry_bridge.ops_by_id('meth1', opcode='STORE_ATTR')) == [] @@ -167,7 +167,7 @@ i70 = int_lt(i58, i33) guard_true(i70, descr=...) guard_not_invalidated(descr=...) - p71 = getfield_gc(p64, descr=...) + p71 = getfield_gc_r(p64, descr=...) guard_value(p71, ConstPtr(ptr42), descr=...) p72 = force_token() p73 = force_token() @@ -175,7 +175,7 @@ i75 = getfield_raw_i(..., descr=...) i76 = int_lt(i75, 0) guard_false(i76, descr=...) - p77 = new_with_vtable(...) + p77 = new_with_vtable(descr=...) setfield_gc(p77, p64, descr=...) setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(null), descr=...) @@ -183,7 +183,7 @@ setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(ptr42), descr=...) setfield_gc(ConstPtr(ptr69), p77, descr=...) - jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, descr=...) + jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, p100, descr=...) """) @@ -209,11 +209,11 @@ assert loop.match_by_id('loadattr1', ''' guard_not_invalidated(descr=...) - i19 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i19 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i22 = int_lt(i19, 0) guard_true(i22, descr=...) - i26 = call(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) + i26 = call_i(ConstClass(ll_call_lookup_function), _, _, _, 0, descr=...) guard_no_exception(descr=...) i29 = int_lt(i26, 0) guard_true(i29, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_math.py b/pypy/module/pypyjit/test_pypy_c/test_math.py --- a/pypy/module/pypyjit/test_pypy_c/test_math.py +++ b/pypy/module/pypyjit/test_pypy_c/test_math.py @@ -23,8 +23,8 @@ f1 = cast_int_to_float(i0) i3 = float_le(f1, 0.0) guard_false(i3, descr=...) - f2 = call(ConstClass(log), f1, descr=) - f3 = call(ConstClass(log10), f1, descr=) + f2 = call_f(ConstClass(log), f1, descr=) + f3 = call_f(ConstClass(log10), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i4 = int_add(i0, 1) @@ -52,8 +52,8 @@ f1 = cast_int_to_float(i0) i6 = --ISINF--(f1) guard_false(i6, descr=...) - f2 = call(ConstClass(sin), f1, descr=) - f3 = call(ConstClass(cos), f1, descr=) + f2 = call_f(ConstClass(sin), f1, descr=) + f3 = call_f(ConstClass(cos), f1, descr=) f4 = float_sub(f2, f3) f5 = float_add(f0, f4) i7 = int_add(i0, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -101,39 +101,39 @@ loop = log._filter(log.loops[0]) assert loop.match(""" guard_class(p1, #, descr=...) - p4 = getfield_gc_pure(p1, descr=) - i5 = getfield_gc(p0, descr=) - p6 = getfield_gc_pure(p4, descr=) - p7 = getfield_gc_pure(p6, descr=) + p4 = getfield_gc_pure_r(p1, descr=) + i5 = getfield_gc_i(p0, descr=) + p6 = getfield_gc_pure_r(p4, descr=) + p7 = getfield_gc_pure_r(p6, descr=) guard_class(p7, ConstClass(Float64), descr=...) - i9 = getfield_gc_pure(p4, descr=) - i10 = getfield_gc_pure(p6, descr=) + i9 = getfield_gc_pure_i(p4, descr=) + i10 = getfield_gc_pure_i(p6, descr=) i12 = int_eq(i10, 61) i14 = int_eq(i10, 60) i15 = int_or(i12, i14) - f16 = raw_load(i9, i5, descr=) + f16 = raw_load_f(i9, i5, descr=) guard_true(i15, descr=...) guard_not_invalidated(descr=...) i18 = float_ne(f16, 0.000000) guard_true(i18, descr=...) guard_nonnull_class(p2, ConstClass(W_BoolBox), descr=...) - i20 = getfield_gc_pure(p2, descr=) + i20 = getfield_gc_pure_i(p2, descr=) i21 = int_is_true(i20) guard_false(i21, descr=...) - i22 = getfield_gc(p0, descr=) - i23 = getfield_gc_pure(p1, descr=) + i22 = getfield_gc_i(p0, descr=) + i23 = getfield_gc_pure_i(p1, descr=) guard_true(i23, descr=...) i25 = int_add(i22, 1) - p26 = getfield_gc_pure(p0, descr=) - i27 = getfield_gc_pure(p1, descr=) + p26 = getfield_gc_pure_r(p0, descr=) + i27 = getfield_gc_pure_i(p1, descr=) i28 = int_is_true(i27) guard_true(i28, descr=...) - i29 = getfield_gc_pure(p6, descr=) + i29 = getfield_gc_pure_i(p6, descr=) i30 = int_add(i5, i29) - i31 = getfield_gc_pure(p1, descr=) + i31 = getfield_gc_pure_i(p1, descr=) i32 = int_ge(i25, i31) guard_false(i32, descr=...) - p34 = new_with_vtable(#) + p34 = new_with_vtable(descr=...) {{{ setfield_gc(p34, p1, descr=) setfield_gc(p34, i25, descr=) @@ -154,13 +154,13 @@ assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - f31 = raw_load(i9, i29, descr=) + f31 = raw_load_f(i9, i29, descr=) guard_not_invalidated(descr=...) i32 = float_ne(f31, 0.000000) guard_true(i32, descr=...) - i34 = getarrayitem_raw(#, #, descr=) # XXX what are these? + i34 = getarrayitem_raw_i(#, #, descr=) # XXX what are these? guard_value(i34, #, descr=...) # XXX don't appear in - i35 = getarrayitem_raw(#, #, descr=) # XXX equiv test_zjit + i35 = getarrayitem_raw_i(#, #, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, 8) i38 = int_ge(i36, i30) @@ -198,7 +198,7 @@ i78 = int_mul(i71, i61) i79 = int_add(i55, i78) """ + alignment_check + """ - f80 = raw_load(i67, i79, descr=) + f80 = raw_load_f(i67, i79, descr=) i81 = int_add(i71, 1) --TICK-- jump(..., descr=...) @@ -235,12 +235,12 @@ i83 = int_mul(i76, i64) i84 = int_add(i58, i83) """ + alignment_check + """ - f85 = raw_load(i70, i84, descr=) + f85 = raw_load_f(i70, i84, descr=) guard_not_invalidated(descr=...) f86 = float_add(f74, f85) i87 = int_add(i76, 1) --TICK-- - jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...) + jump(..., descr=...) """) def test_array_flatiter_next(self): @@ -262,7 +262,7 @@ guard_not_invalidated(descr=...) i88 = int_ge(i87, i59) guard_false(i88, descr=...) - f90 = raw_load(i67, i89, descr=) + f90 = raw_load_f(i67, i89, descr=) i91 = int_add(i87, 1) i93 = int_add(i89, 8) i94 = int_add(i79, 1) @@ -294,11 +294,11 @@ guard_true(i126, descr=...) i128 = int_mul(i117, i59) i129 = int_add(i55, i128) - f149 = raw_load(i100, i129, descr=) + f149 = raw_load_f(i100, i129, descr=) i151 = int_add(i117, 1) + setfield_gc(p156, i55, descr=) setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) - setfield_gc(p156, i55, descr=) --TICK-- jump(..., descr=...) """) @@ -327,9 +327,9 @@ raw_store(i103, i132, 42.000000, descr=) i153 = int_add(i120, 1) i154 = getfield_raw_i(#, descr=) + setfield_gc(p158, i53, descr=) setarrayitem_gc(p152, 1, 0, descr=) setarrayitem_gc(p152, 0, 0, descr=) - setfield_gc(p158, i53, descr=) i157 = int_lt(i154, 0) guard_false(i157, descr=...) jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -38,7 +38,7 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) loop2 = log.loops[0] @@ -50,11 +50,11 @@ guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) - p18 = getarrayitem_gc(p5, i11, descr=...) + p18 = getarrayitem_gc_r(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) - i20 = getfield_gc_pure(p18, descr=...) + i20 = getfield_gc_pure_i(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) @@ -79,6 +79,6 @@ assert len(guards) < 20 assert loop.match(""" ... - p76 = call_assembler(_, _, _, _, descr=...) + p76 = call_assembler_r(_, _, _, _, descr=...) ... """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -65,7 +65,7 @@ assert loop.match(""" i7 = int_gt(i4, 1) guard_true(i7, descr=...) - p11 = call(ConstClass(rbigint.int_mul), p5, i4, descr=...) + p11 = call_r(ConstClass(rbigint.int_mul), p5, i4, descr=...) guard_no_exception(descr=...) i13 = int_sub(i4, 1) --TICK-- @@ -113,14 +113,14 @@ i12 = int_is_true(i4) guard_true(i12, descr=...) guard_not_invalidated(descr=...) - i13 = int_add_ovf(i8, i9) - guard_no_overflow(descr=...) - i10p = getfield_gc_pure(p10, descr=...) + i10p = getfield_gc_pure_i(p10, descr=...) i10 = int_mul_ovf(2, i10p) guard_no_overflow(descr=...) i14 = int_add_ovf(i13, i10) guard_no_overflow(descr=...) - setfield_gc(p7, p11, descr=...) + i13 = int_add_ovf(i14, i9) + guard_no_overflow(descr=...) + setfield_gc(p17, p10, descr=...) i17 = int_sub_ovf(i4, 1) guard_no_overflow(descr=...) --TICK-- @@ -148,6 +148,7 @@ i18 = force_token() setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>) guard_not_invalidated(descr=...) + i84 = int_sub(i14, 1) i21 = int_lt(i10, 0) guard_false(i21, descr=...) i22 = int_lt(i10, i14) @@ -180,6 +181,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i88 = int_sub(i9, 1) i25 = int_ge(i11, i9) guard_false(i25, descr=...) i27 = int_add_ovf(i7, i11) @@ -212,6 +214,7 @@ i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i95 = int_sub(i9, 1) i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) @@ -260,25 +263,24 @@ loop, = log.loops_by_filename(self.filepath) assert loop.match(""" guard_not_invalidated? - i14 = getfield_gc(p12, descr=) i16 = uint_ge(i12, i14) guard_false(i16, descr=...) - p16 = getfield_gc(p12, descr=) - p17 = getarrayitem_gc(p16, i12, descr=) + p17 = getarrayitem_gc_r(p16, i12, descr=) i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) guard_not_invalidated? - i21 = getfield_gc(p17, descr=) + i21 = getfield_gc_i(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) - i24 = getfield_gc(p17, descr=) - i25 = getarrayitem_raw(i24, 0, descr=<.*>) + i24 = getfield_gc_i(p17, descr=) + i25 = getarrayitem_raw_i(i24, 0, descr=<.*>) i27 = int_lt(1, i21) guard_false(i27, descr=...) i28 = int_add_ovf(i10, i25) guard_no_overflow(descr=...) --TICK-- + if00 = arraylen_gc(p16, descr=...) jump(..., descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -43,9 +43,9 @@ i25 = unicodegetitem(p13, i19) p27 = newstr(1) strsetitem(p27, 0, i23) - p30 = call(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) + p30 = call_r(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...) guard_no_exception(descr=...) - i32 = call(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) + i32 = call_i(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...) guard_true(i32, descr=...) i34 = int_add(i6, 1) --TICK-- @@ -80,12 +80,12 @@ i23 = strgetitem(p10, i19) p25 = newstr(1) strsetitem(p25, 0, i23) - p93 = call(ConstClass(fromstr), p25, 16, descr=) + p93 = call_r(ConstClass(fromstr), p25, 16, descr=) guard_no_exception(descr=...) - i95 = getfield_gc_pure(p93, descr=) + i95 = getfield_gc_pure_i(p93, descr=) i96 = int_gt(i95, #) guard_false(i96, descr=...) - i94 = call(ConstClass(rbigint._toint_helper), p93, descr=) + i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=) guard_no_exception(descr=...) i95 = int_add_ovf(i6, i94) guard_no_overflow(descr=...) @@ -108,7 +108,7 @@ i79 = int_gt(i74, 0) guard_true(i79, descr=...) guard_not_invalidated(descr=...) - p80 = call(ConstClass(ll_int2dec__Signed), i74, descr=) + p80 = call_r(ConstClass(ll_int2dec__Signed), i74, descr=) guard_no_exception(descr=...) i85 = strlen(p80) p86 = new(descr=) @@ -119,21 +119,21 @@ setfield_gc(p86, 23, descr=) setfield_gc(p86, 23, descr=) }}} - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - i89 = getfield_gc(p86, descr=) - i90 = getfield_gc(p86, descr=) + i89 = getfield_gc_i(p86, descr=) + i90 = getfield_gc_i(p86, descr=) i91 = int_eq(i89, i90) cond_call(i91, ConstClass(ll_grow_by__stringbuilderPtr_Signed), p86, 1, descr=) guard_no_exception(descr=...) - i92 = getfield_gc(p86, descr=) + i92 = getfield_gc_i(p86, descr=) i93 = int_add(i92, 1) - p94 = getfield_gc(p86, descr=) + p94 = getfield_gc_r(p86, descr=) strsetitem(p94, i92, 32) setfield_gc(p86, i93, descr=) - call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) + call_n(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), p86, p80, descr=) guard_no_exception(descr=...) - p95 = call(..., descr=) # ll_build + p95 = call_r(..., descr=) # ll_build guard_no_exception(descr=...) i96 = strlen(p95) i97 = int_add_ovf(i71, i96) @@ -176,7 +176,7 @@ strsetitem(p35, 3, 104) strsetitem(p35, 4, 95) copystrcontent(p31, p35, 0, 5, i32) - i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) + i49 = call_i(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=) guard_value(i49, 1, descr=...) ''') @@ -195,7 +195,7 @@ loops = log.loops_by_filename(self.filepath) loop, = loops assert loop.match_by_id('callone', ''' - p114 = call(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) + p114 = call_r(ConstClass(ll_lower__rpy_stringPtr), p113, descr=) guard_no_exception(descr=...) ''') assert loop.match_by_id('calltwo', '') # nothing @@ -248,9 +248,9 @@ i50 = int_add(i47, 1) setfield_gc(p15, i50, descr=) guard_not_invalidated(descr=...) - p80 = call(ConstClass(ll_str__IntegerR_SignedConst_Signed), i47, descr=) + p80 = call_r(ConstClass(ll_str__IntegerR_SignedConst_Signed), i47, descr=) guard_no_exception(descr=...) - p53 = call(ConstClass(fast_str_decode_ascii), p80, descr=) + p53 = call_r(ConstClass(fast_str_decode_ascii), p80, descr=) guard_no_exception(descr=...) guard_nonnull(p53, descr=...) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py --- a/pypy/module/pypyjit/test_pypy_c/test_thread.py +++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py @@ -64,11 +64,11 @@ guard_true(i56, descr=...) p57 = force_token() setfield_gc(p0, p57, descr=) - i58 = call_release_gil(0, _, i37, 1, descr=) + i58 = call_release_gil_i(0, _, i37, 1, descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) i58 = int_sub(i44, 1) - i59 = call(ConstClass(RPyThreadReleaseLock), i37, descr=) + i59 = call_i(ConstClass(RPyThreadReleaseLock), i37, descr=) i60 = int_is_true(i59) guard_false(i60, descr=...) guard_not_invalidated(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_weakref.py b/pypy/module/pypyjit/test_pypy_c/test_weakref.py --- a/pypy/module/pypyjit/test_pypy_c/test_weakref.py +++ b/pypy/module/pypyjit/test_pypy_c/test_weakref.py @@ -19,23 +19,23 @@ """, [500]) loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - i58 = getfield_gc(p18, descr=) + i58 = getfield_gc_i(p18, descr=) i60 = int_lt(i58, i31) guard_true(i60, descr=...) i61 = int_add(i58, 1) - p62 = getfield_gc(ConstPtr(ptr37), descr=) + p62 = getfield_gc_r(ConstPtr(ptr37), descr=) setfield_gc(p18, i61, descr=) guard_value(p62, ConstPtr(ptr39), descr=...) guard_not_invalidated(descr=...) - p64 = getfield_gc(ConstPtr(ptr40), descr=) + p64 = getfield_gc_r(ConstPtr(ptr40), descr=) guard_value(p64, ConstPtr(ptr42), descr=...) - p65 = getfield_gc(p14, descr=) + p65 = getfield_gc_r(p14, descr=) guard_value(p65, ConstPtr(ptr45), descr=...) - p66 = getfield_gc(p14, descr=) + p66 = getfield_gc_r(p14, descr=) guard_nonnull_class(p66, ..., descr=...) p67 = force_token() setfield_gc(p0, p67, descr=) - p68 = call_may_force(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) + p68 = call_may_force_r(ConstClass(WeakrefLifelineWithCallbacks.make_weakref_with_callback), p66, ConstPtr(ptr50), p14, ConstPtr(ptr51), descr=) guard_not_forced(descr=...) guard_no_exception(descr=...) guard_nonnull_class(p68, ..., descr=...) diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -123,23 +123,26 @@ self.sig_recvd = True old_handler = signal.signal(signal.SIGUSR1, my_handler) try: + ready = thread.allocate_lock() + ready.acquire() def other_thread(): # Acquire the lock in a non-main thread, so this test works for # RLocks. lock.acquire() - # Wait until the main thread is blocked in the lock acquire, and - # then wake it up with this. - time.sleep(0.5) + # Notify the main thread that we're ready + ready.release() + # Wait for 5 seconds here + for n in range(50): From noreply at buildbot.pypy.org Tue Sep 29 17:25:33 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Tue, 29 Sep 2015 17:25:33 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: fixing tests in metainterp/test Message-ID: <20150929152534.05B611C04C6@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79897:084da9225f35 Date: 2015-09-29 17:25 +0200 http://bitbucket.org/pypy/pypy/changeset/084da9225f35/ Log: fixing tests in metainterp/test diff --git a/rpython/jit/metainterp/optimizeopt/schedule.py b/rpython/jit/metainterp/optimizeopt/schedule.py --- a/rpython/jit/metainterp/optimizeopt/schedule.py +++ b/rpython/jit/metainterp/optimizeopt/schedule.py @@ -216,11 +216,17 @@ class OpMatchSizeTypeFirst(OpRestrict): def check_operation(self, state, pack, op): - arg0 = op.getarg(0) + i = 0 + arg0 = op.getarg(i) + while arg0.is_constant() and i < op.numargs(): + i += 1 + arg0 = op.getarg(i) bytesize = arg0.bytesize datatype = arg0.datatype for arg in op.getarglist(): + if arg.is_constant(): + continue if arg.bytesize != bytesize: raise NotAVectorizeableLoop() if arg.datatype != datatype: 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 @@ -20,7 +20,7 @@ b1 = InputArgInt() opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu), None, None) - op = ResOperation(rop.GUARD_TRUE, ['dummy'], None) + op = ResOperation(rop.GUARD_TRUE, [ConstInt(1)], None) # setup rd data fi0 = resume.FrameInfo(None, "code0", 11) snapshot0 = resume.Snapshot(None, [b0]) diff --git a/rpython/jit/metainterp/test/test_resoperation.py b/rpython/jit/metainterp/test/test_resoperation.py --- a/rpython/jit/metainterp/test/test_resoperation.py +++ b/rpython/jit/metainterp/test/test_resoperation.py @@ -56,13 +56,15 @@ assert INT_SUB.__bases__[0] is BinaryPlainResOp def test_instantiate(): - op = rop.ResOperation(rop.rop.INT_ADD, ['a', 'b']) - assert op.getarglist() == ['a', 'b'] + a = ConstInt(1) + b = ConstInt(2) + op = rop.ResOperation(rop.rop.INT_ADD, [a, b]) + assert op.getarglist() == [a, b] #assert re.match(".*= int_add(a, b)", repr(op)) mydescr = AbstractDescr() - op = rop.ResOperation(rop.rop.CALL_I, ['a', 'b'], descr=mydescr) - assert op.getarglist() == ['a', 'b'] + op = rop.ResOperation(rop.rop.CALL_I, [a, b], descr=mydescr) + assert op.getarglist() == [a, b] assert op.getdescr() is mydescr #assert re.match(".* = call\(a, b, descr=<.+>\)$", repr(op)) @@ -71,28 +73,39 @@ #assert re.match("guard_no_exception\(descr=<.+>\)$", repr(op)) def test_can_malloc(): + a = ConstInt(1) + b = ConstInt(2) mydescr = AbstractDescr() assert rop.ResOperation(rop.rop.NEW, []).can_malloc() - call = rop.ResOperation(rop.rop.CALL_N, ['a', 'b'], descr=mydescr) + call = rop.ResOperation(rop.rop.CALL_N, [a, b], descr=mydescr) assert call.can_malloc() - assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b']).can_malloc() + assert not rop.ResOperation(rop.rop.INT_ADD, [a, b]).can_malloc() def test_get_deep_immutable_oplist(): - ops = [rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'])] + a = ConstInt(1) + b = ConstInt(2) + ops = [rop.ResOperation(rop.rop.INT_ADD, [a, b])] newops = rop.get_deep_immutable_oplist(ops) py.test.raises(TypeError, "newops.append('foobar')") py.test.raises(TypeError, "newops[0] = 'foobar'") py.test.raises(AssertionError, "newops[0].setarg(0, 'd')") py.test.raises(AssertionError, "newops[0].setdescr('foobar')") -def test_cast_ops(): - op = rop.ResOperation(rop.rop.INT_SIGNEXT, ['a', ConstInt(1)], 'c') - assert op.casts_box() - assert isinstance(op, rop.CastResOp) - assert op.cast_to() == ('i',1) - op = rop.ResOperation(rop.rop.CAST_FLOAT_TO_INT, ['a'], 'c') - assert op.casts_box() - assert isinstance(op, rop.CastResOp) +VARI = rop.InputArgInt() +VARF = rop.InputArgFloat() + at py.test.mark.parametrize('opnum,args,kwargs', + [ (rop.rop.INT_SIGNEXT, [VARI, ConstInt(2)], {'from': 8, 'to': 2, 'cast_to': ('i', 2) }), + (rop.rop.CAST_FLOAT_TO_INT, [VARF], {'from': 8, 'to': 4}), + (rop.rop.CAST_SINGLEFLOAT_TO_FLOAT, [VARI], {'from': 4, 'to': 8}), + (rop.rop.CAST_FLOAT_TO_SINGLEFLOAT, [VARF], {'from': 8, 'to': 4}), + ]) +def test_cast_ops(opnum, args, kwargs): + op = rop.ResOperation(opnum, args) + assert op.is_typecast() + assert op.cast_from_bytesize() == kwargs['from'] + assert op.cast_to_bytesize() == kwargs['to'] + if 'cast_to' in kwargs: + assert op.cast_to() == kwargs['cast_to'] def test_types(): op = rop.ResOperation(rop.rop.INT_ADD, [ConstInt(0),ConstInt(1)]) From noreply at buildbot.pypy.org Tue Sep 29 19:32:06 2015 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 29 Sep 2015 19:32:06 +0200 (CEST) Subject: [pypy-commit] pypy default: enable _vmprof on os x by default Message-ID: <20150929173206.75FCB1C12AA@cobra.cs.uni-duesseldorf.de> Author: fijal Branch: Changeset: r79898:42682d78903c Date: 2015-09-29 19:32 +0200 http://bitbucket.org/pypy/pypy/changeset/42682d78903c/ Log: enable _vmprof on os x by default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -39,8 +39,9 @@ "_csv", "cppyy", "_pypyjson" ]) -if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64' - and sys.maxint > 2**32): # it's not enough that we get x86_64 +if ((sys.platform.startswith('linux') or sys.platform == 'darwin') + and os.uname()[4] == 'x86_64' and sys.maxint > 2**32): + # it's not enough that we get x86_64 working_modules.add('_vmprof') translation_modules = default_modules.copy() From noreply at buildbot.pypy.org Wed Sep 30 00:38:41 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 00:38:41 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: a branch to support fortran-ordered ndarrays Message-ID: <20150929223841.565221C13BE@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79899:164c3e664fa0 Date: 2015-09-29 17:15 +0300 http://bitbucket.org/pypy/pypy/changeset/164c3e664fa0/ Log: a branch to support fortran-ordered ndarrays From noreply at buildbot.pypy.org Wed Sep 30 00:38:43 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 00:38:43 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: convert internal use of order from a char to an enum Message-ID: <20150929223843.95D171C13BE@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79900:4666c894b561 Date: 2015-09-30 01:38 +0300 http://bitbucket.org/pypy/pypy/changeset/4666c894b561/ Log: convert internal use of order from a char to an enum diff --git a/pypy/module/micronumpy/arrayops.py b/pypy/module/micronumpy/arrayops.py --- a/pypy/module/micronumpy/arrayops.py +++ b/pypy/module/micronumpy/arrayops.py @@ -140,7 +140,7 @@ dtype = find_result_type(space, args_w, []) # concatenate does not handle ndarray subtypes, it always returns a ndarray - res = W_NDimArray.from_shape(space, shape, dtype, 'C') + res = W_NDimArray.from_shape(space, shape, dtype, NPY.CORDER) chunks = [Chunk(0, i, 1, i) for i in shape] axis_start = 0 for arr in args_w: diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -38,7 +38,8 @@ self.implementation = implementation @staticmethod - def from_shape(space, shape, dtype, order='C', w_instance=None, zero=True): + def from_shape(space, shape, dtype, order=NPY.CORDER, + w_instance=None, zero=True): from pypy.module.micronumpy import concrete, descriptor, boxes from pypy.module.micronumpy.strides import calc_strides if len(shape) > NPY.MAXDIMS: @@ -59,8 +60,9 @@ @staticmethod def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, - order='C', owning=False, w_subtype=None, - w_base=None, writable=True, strides=None, start=0): + order=NPY.CORDER, owning=False, w_subtype=None, + w_base=None, writable=True, strides=None, + start=0): from pypy.module.micronumpy import concrete from pypy.module.micronumpy.strides import (calc_strides, calc_backstrides) diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -56,6 +56,9 @@ jit.hint(len(backstrides), promote=True) return backstrides + def get_flags(self): + return self.flags + def getitem(self, index): return self.dtype.read(self, index, 0) @@ -360,12 +363,12 @@ # but make the array storage contiguous in memory shape = self.get_shape() strides = self.get_strides() - if order not in ('C', 'F'): - raise oefmt(space.w_ValueError, "Unknown order %s in astype", order) + if order not in (NPY.KEEPORDER, NPY.FORTRANORDER, NPY.CORDER): + raise oefmt(space.w_ValueError, "Unknown order %d in astype", order) if len(strides) == 0: t_strides = [] backstrides = [] - elif order != self.order: + elif order in (NPY.FORTRANORDER, NPY.CORDER): t_strides, backstrides = calc_strides(shape, dtype, order) else: indx_array = range(len(strides)) @@ -602,13 +605,13 @@ s = self.get_strides()[0] // dtype.elsize except IndexError: s = 1 - if self.order == 'C': + if self.order != NPY.FORTRANORDER: new_shape.reverse() for sh in new_shape: strides.append(s * dtype.elsize) backstrides.append(s * (sh - 1) * dtype.elsize) s *= max(1, sh) - if self.order == 'C': + if self.order != NPY.FORTRANORDER: strides.reverse() backstrides.reverse() new_shape.reverse() diff --git a/pypy/module/micronumpy/converters.py b/pypy/module/micronumpy/converters.py --- a/pypy/module/micronumpy/converters.py +++ b/pypy/module/micronumpy/converters.py @@ -77,9 +77,8 @@ elif order.startswith('K') or order.startswith('k'): return NPY.KEEPORDER else: - raise OperationError(space.w_TypeError, space.wrap( - "order not understood")) - + raise oefmt(space.w_TypeError, "Unknown order: '%s'", order) + return -1 def multi_axis_converter(space, w_axis, ndim): if space.is_none(w_axis): diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -4,9 +4,10 @@ from rpython.rlib.rstring import strip_spaces from rpython.rtyper.lltypesystem import lltype, rffi from pypy.module.micronumpy import descriptor, loop, support -from pypy.module.micronumpy.base import ( +from pypy.module.micronumpy.base import (wrap_impl, W_NDimArray, convert_to_array, W_NumpyObject) -from pypy.module.micronumpy.converters import shape_converter +from pypy.module.micronumpy.converters import shape_converter, order_converter +import pypy.module.micronumpy.constants as NPY def build_scalar(space, w_dtype, w_state): @@ -99,13 +100,8 @@ dtype = descriptor.decode_w_dtype(space, w_dtype) if space.is_none(w_order): - order = 'C' - else: - order = space.str_w(w_order) - if order == 'K': - order = 'C' - if order != 'C': # or order != 'F': - raise oefmt(space.w_ValueError, "Unknown order: %s", order) + w_order = space.wrap('C') + npy_order = order_converter(space, w_order, NPY.CORDER) if isinstance(w_object, W_NDimArray): if (dtype is None or w_object.get_dtype() is dtype): @@ -124,7 +120,7 @@ copy = True if copy: shape = w_object.get_shape() - w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) + w_arr = W_NDimArray.from_shape(space, shape, dtype, order=npy_order) if support.product(shape) == 1: w_arr.set_scalar_value(dtype.coerce(space, w_object.implementation.getitem(0))) @@ -154,7 +150,7 @@ # promote S0 -> S1, U0 -> U1 dtype = descriptor.variable_dtype(space, dtype.char + '1') - w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) + w_arr = W_NDimArray.from_shape(space, shape, dtype, order=npy_order) if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: @@ -230,6 +226,7 @@ @unwrap_spec(subok=bool) def empty_like(space, w_a, w_dtype=None, w_order=None, subok=True): w_a = convert_to_array(space, w_a) + npy_order = order_converter(space, w_order, w_a.get_order()) if space.is_none(w_dtype): dtype = w_a.get_dtype() else: @@ -237,7 +234,16 @@ space.call_function(space.gettypefor(descriptor.W_Dtype), w_dtype)) if dtype.is_str_or_unicode() and dtype.elsize < 1: dtype = descriptor.variable_dtype(space, dtype.char + '1') + if npy_order == NPY.KEEPORDER: + # Try to copy the stride pattern + impl = w_a.implementation.astype(space, dtype, npy_order) + if subok: + w_type = space.type(w_a) + else: + w_type = None + return wrap_impl(space, w_type, w_a, impl) return W_NDimArray.from_shape(space, w_a.get_shape(), dtype=dtype, + order=npy_order, w_instance=w_a if subok else None, zero=False) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -680,7 +680,8 @@ def tostring(space, arr): builder = StringBuilder() iter, state = arr.create_iter() - w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), order='C') + w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), + order=NPY.CORDER) itemsize = arr.get_dtype().elsize with w_res_str.implementation as storage: res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char), diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -97,7 +97,10 @@ self.fill(space, self.get_dtype().coerce(space, w_value)) def descr_tostring(self, space, w_order=None): - order = order_converter(space, w_order, NPY.CORDER) + try: + order = order_converter(space, w_order, NPY.CORDER) + except OperationError as e: + raise oefmt(space.w_TypeError, "order not understood") if order == NPY.FORTRANORDER: raise OperationError(space.w_NotImplementedError, space.wrap( "unsupported value for order")) @@ -365,7 +368,12 @@ return self.implementation.getitem(self.implementation.start) def descr_copy(self, space, w_order=None): - order = order_converter(space, w_order, NPY.KEEPORDER) + if w_order is None: + order = NPY.KEEPORDER + elif space.isinstance_w(w_order, space.w_int): + order = space.int_w(w_order) + else: + order = order_converter(space, w_order, NPY.KEEPORDER) if order == NPY.FORTRANORDER: raise OperationError(space.w_NotImplementedError, space.wrap( "unsupported value for order")) @@ -631,7 +639,7 @@ space.newtuple([space.wrap(addr), space.w_False])) space.setitem_str(w_d, 'shape', self.descr_get_shape(space)) space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space)) - if self.implementation.order == 'C': + if self.implementation.order == NPY.CORDER: # Array is contiguous, no strides in the interface. strides = space.w_None else: @@ -690,8 +698,9 @@ "according to the rule %s", space.str_w(self.get_dtype().descr_repr(space)), space.str_w(new_dtype.descr_repr(space)), casting) - order = support.get_order_as_CF(self.get_order(), order) - if (not copy and new_dtype == self.get_dtype() and order == self.get_order() + order = order_converter(space, space.wrap(order), self.get_order()) + if (not copy and new_dtype == self.get_dtype() + and (order in (NPY.KEEPORDER, NPY.ANYORDER) or order == self.get_order()) and (subok or type(self) is W_NDimArray)): return self impl = self.implementation @@ -970,7 +979,7 @@ raise OperationError(space.w_ValueError, space.wrap( "new type not compatible with array.")) # Adapt the smallest dim to the new itemsize - if self.get_order() == 'F': + if self.get_order() == NPY.FORTRANORDER: minstride = strides[0] mini = 0 else: @@ -1134,7 +1143,7 @@ matches = True if dtype != out.get_dtype(): matches = False - elif not out.implementation.order == "C": + elif not out.implementation.order == NPY.CORDER: matches = False elif out.ndims() != len(out_shape): matches = False @@ -1403,10 +1412,6 @@ strides=strides) order = order_converter(space, w_order, NPY.CORDER) - if order == NPY.CORDER: - order = 'C' - else: - order = 'F' if space.is_w(w_subtype, space.gettypefor(W_NDimArray)): return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) @@ -1443,7 +1448,7 @@ raise OperationError(space.w_ValueError, space.wrap( "subtype must be a subtype of ndarray, not a class instance")) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, - buf_len, 'C', False, w_subtype, + buf_len, NPY.CORDER, False, w_subtype, strides=strides) else: return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -11,6 +11,8 @@ shape_agreement, shape_agreement_multiple) from pypy.module.micronumpy.casting import (find_binop_result_dtype, can_cast_array, can_cast_type) +import pypy.module.micronumpy.constants as NPY +from pypy.module.micronumpy.converters import order_converter def parse_op_arg(space, name, w_op_flags, n, parse_one_arg): @@ -144,9 +146,9 @@ def is_backward(imp, order): - if order == 'K' or (order == 'C' and imp.order == 'C'): + if order == NPY.KEEPORDER or (order == NPY.CORDER and imp.order == NPY.CORDER): return False - elif order == 'F' and imp.order == 'C': + elif order == NPY.FORTRANORDER and imp.order == NPY.CORDER: return True else: raise NotImplementedError('not implemented yet') @@ -234,7 +236,7 @@ continue assert isinstance(op_it, ArrayIter) indx = len(op_it.strides) - if it.order == 'F': + if it.order == NPY.FORTRANORDER: indx = len(op_it.array.strides) - indx assert indx >=0 astrides = op_it.array.strides[indx:] @@ -250,7 +252,7 @@ it.order) it.iters[i] = (new_iter, new_iter.reset()) if len(it.shape) > 1: - if it.order == 'F': + if it.order == NPY.FORTRANORDER: it.shape = it.shape[1:] else: it.shape = it.shape[:-1] @@ -261,10 +263,10 @@ break # Always coalesce at least one for i in range(len(it.iters)): - new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C') + new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, NPY.CORDER) it.iters[i] = (new_iter, new_iter.reset()) if len(it.shape) > 1: - if it.order == 'F': + if it.order == NPY.FORTRANORDER: it.shape = it.shape[1:] else: it.shape = it.shape[:-1] @@ -287,7 +289,7 @@ return old_iter strides = old_iter.strides backstrides = old_iter.backstrides - if order == 'F': + if order == NPY.FORTRANORDER: new_shape = shape[1:] new_strides = strides[1:] new_backstrides = backstrides[1:] @@ -346,7 +348,8 @@ class W_NDIter(W_NumpyObject): _immutable_fields_ = ['ndim', ] def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, - w_casting, w_op_axes, w_itershape, buffersize=0, order='K'): + w_casting, w_op_axes, w_itershape, buffersize=0, + order=NPY.KEEPORDER): self.order = order self.external_loop = False self.buffered = False @@ -439,12 +442,15 @@ str(self.shape)) if self.tracked_index != "": - if self.order == "K": - self.order = self.seq[0].implementation.order + order = self.order + if order == NPY.KEEPORDER: + order = self.seq[0].implementation.order if self.tracked_index == "multi": backward = False else: - backward = self.order != self.tracked_index + backward = (( + order == NPY.CORDER and self.tracked_index != 'C') or ( + order == NPY.FORTRANORDER and self.tracked_index != 'F')) self.index_iter = IndexIterator(self.shape, backward=backward) # handle w_op_dtypes part 2: copy where needed if possible @@ -456,7 +462,6 @@ self.dtypes[i] = seq_d elif self_d != seq_d: impl = self.seq[i].implementation - order = support.get_order_as_CF(impl.order, self.order) if self.buffered or 'r' in self.op_flags[i].tmp_copy: if not can_cast_array( space, self.seq[i], self_d, self.casting): @@ -466,7 +471,7 @@ space.str_w(seq_d.descr_repr(space)), space.str_w(self_d.descr_repr(space)), self.casting) - + order = support.get_order_as_CF(impl.order, self.order) new_impl = impl.astype(space, self_d, order).copy(space) self.seq[i] = W_NDimArray(new_impl) else: @@ -704,13 +709,15 @@ @unwrap_spec(w_flags=WrappedDefault(None), w_op_flags=WrappedDefault(None), - w_op_dtypes=WrappedDefault(None), order=str, + w_op_dtypes=WrappedDefault(None), w_order=WrappedDefault(None), w_casting=WrappedDefault(None), w_op_axes=WrappedDefault(None), - w_itershape=WrappedDefault(None), buffersize=int) + w_itershape=WrappedDefault(None), w_buffersize=WrappedDefault(0)) def descr_new_nditer(space, w_subtype, w_seq, w_flags, w_op_flags, w_op_dtypes, - w_casting, w_op_axes, w_itershape, buffersize=0, order='K'): + w_casting, w_op_axes, w_itershape, w_buffersize, w_order): + npy_order = order_converter(space, w_order, NPY.KEEPORDER) + buffersize = space.int_w(w_buffersize) return W_NDIter(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, - w_itershape, buffersize, order) + w_itershape, buffersize, npy_order) W_NDIter.typedef = TypeDef('numpy.nditer', __new__ = interp2app(descr_new_nditer), diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py --- a/pypy/module/micronumpy/strides.py +++ b/pypy/module/micronumpy/strides.py @@ -371,14 +371,14 @@ backstrides = [] s = 1 shape_rev = shape[:] - if order == 'C': + if order in [NPY.CORDER, NPY.ANYORDER]: shape_rev.reverse() for sh in shape_rev: slimit = max(sh, 1) strides.append(s * dtype.elsize) backstrides.append(s * (slimit - 1) * dtype.elsize) s *= slimit - if order == 'C': + if order in [NPY.CORDER, NPY.ANYORDER]: strides.reverse() backstrides.reverse() return strides, backstrides @@ -406,7 +406,7 @@ last_step = 1 oldI = 0 new_strides = [] - if order == 'F': + if order == NPY.FORTRANORDER: for i in range(len(old_shape)): steps.append(old_strides[i] / last_step) last_step *= old_shape[i] @@ -426,7 +426,7 @@ if oldI < len(old_shape): cur_step = steps[oldI] n_old_elems_to_use *= old_shape[oldI] - elif order == 'C': + else: for i in range(len(old_shape) - 1, -1, -1): steps.insert(0, old_strides[i] / last_step) last_step *= old_shape[i] diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -7,6 +7,7 @@ from pypy.interpreter.typedef import GetSetProperty from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.objspace import StdObjSpace +from pypy.module.micronumpy import constants as NPY def issequence_w(space, w_obj): from pypy.module.micronumpy.base import W_NDimArray @@ -173,15 +174,11 @@ return space.is_true(space.gt(w_priority_r, w_priority_l)) def get_order_as_CF(proto_order, req_order): - if req_order == 'C': - return 'C' - elif req_order == 'F': - return 'F' - elif req_order == 'K': - return proto_order - elif req_order == 'A': - return proto_order - + if req_order == NPY.CORDER: + return NPY.CORDER + elif req_order == NPY.FORTRANORDER: + return NPY.FORTRANORDER + return proto_order def descr_set_docstring(space, w_obj, w_docstring): if not isinstance(space, StdObjSpace): diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -6,6 +6,7 @@ from pypy.module.micronumpy.appbridge import get_appbridge_cache from pypy.module.micronumpy.strides import Chunk, new_view, EllipsisChunk from pypy.module.micronumpy.ndarray import W_NDimArray +import pypy.module.micronumpy.constants as NPY from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest @@ -45,20 +46,20 @@ return self.space.newtuple(args_w) def test_strides_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) assert a.strides == [1, 10, 50] assert a.backstrides == [9, 40, 100] def test_strides_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) assert a.strides == [15, 3, 1] assert a.backstrides == [135, 12, 2] - a = create_array(self.space, [1, 0, 7], MockDtype(), order='C') + a = create_array(self.space, [1, 0, 7], MockDtype(), order=NPY.CORDER) assert a.strides == [7, 7, 1] assert a.backstrides == [0, 0, 6] def test_create_slice_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(3, 0, 0, 1)]) assert s.start == 3 assert s.strides == [10, 50] @@ -77,7 +78,7 @@ assert s.shape == [10, 3] def test_create_slice_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(3, 0, 0, 1)]) assert s.start == 45 assert s.strides == [3, 1] @@ -97,7 +98,7 @@ assert s.shape == [10, 3] def test_slice_of_slice_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(5, 0, 0, 1)]) assert s.start == 5 s2 = create_slice(self.space, s, [Chunk(3, 0, 0, 1)]) @@ -114,7 +115,7 @@ assert s2.start == 1 * 15 + 2 * 3 def test_slice_of_slice_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(5, 0, 0, 1)]) assert s.start == 15 * 5 s2 = create_slice(self.space, s, [Chunk(3, 0, 0, 1)]) @@ -131,14 +132,14 @@ assert s2.start == 1 * 15 + 2 * 3 def test_negative_step_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(9, -1, -2, 5)]) assert s.start == 9 assert s.strides == [-2, 10, 50] assert s.backstrides == [-8, 40, 100] def test_negative_step_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(9, -1, -2, 5)]) assert s.start == 135 assert s.strides == [-30, 3, 1] @@ -155,17 +156,17 @@ def test_calc_new_strides(self): from pypy.module.micronumpy.strides import calc_new_strides - assert calc_new_strides([2, 4], [4, 2], [4, 2], "C") == [8, 2] - assert calc_new_strides([2, 4, 3], [8, 3], [1, 16], 'F') == [1, 2, 16] - assert calc_new_strides([2, 3, 4], [8, 3], [1, 16], 'F') is None - assert calc_new_strides([24], [2, 4, 3], [48, 6, 1], 'C') is None - assert calc_new_strides([24], [2, 4, 3], [24, 6, 2], 'C') == [2] - assert calc_new_strides([105, 1], [3, 5, 7], [35, 7, 1],'C') == [1, 1] - assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],'C') == [105, 1] - assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],'F') is None - assert calc_new_strides([1, 1, 1, 105, 1], [15, 7], [7, 1],'C') == \ + assert calc_new_strides([2, 4], [4, 2], [4, 2], NPY.CORDER) == [8, 2] + assert calc_new_strides([2, 4, 3], [8, 3], [1, 16], NPY.FORTRANORDER) == [1, 2, 16] + assert calc_new_strides([2, 3, 4], [8, 3], [1, 16], NPY.FORTRANORDER) is None + assert calc_new_strides([24], [2, 4, 3], [48, 6, 1], NPY.CORDER) is None + assert calc_new_strides([24], [2, 4, 3], [24, 6, 2], NPY.CORDER) == [2] + assert calc_new_strides([105, 1], [3, 5, 7], [35, 7, 1],NPY.CORDER) == [1, 1] + assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],NPY.CORDER) == [105, 1] + assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],NPY.FORTRANORDER) is None + assert calc_new_strides([1, 1, 1, 105, 1], [15, 7], [7, 1],NPY.CORDER) == \ [105, 105, 105, 1, 1] - assert calc_new_strides([1, 1, 105, 1, 1], [7, 15], [1, 7],'F') == \ + assert calc_new_strides([1, 1, 105, 1, 1], [7, 15], [1, 7],NPY.FORTRANORDER) == \ [1, 1, 1, 105, 105] def test_find_shape(self): diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py --- a/pypy/module/micronumpy/test/test_nditer.py +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -120,8 +120,8 @@ skip('Fortran order not implemented') it = nditer([a, b]) - - assert list(it) == zip(range(1, 5), range(1, 5)) + r = list(it) + assert r == zip(range(1, 5), range(1, 5)) def test_interface(self): from numpy import arange, nditer, zeros diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -667,9 +667,9 @@ for dt_in, dt_out in self.dtypes: if can_cast_to(dtype, dt_in) and dt_out == dt_in: return dt_in - raise ValueError( + raise oefmt(space.w_ValueError, "could not find a matching type for %s.accumulate, " - "requested type has type code '%s'" % (self.name, dtype.char)) + "requested type has type code '%s'", self.name, dtype.char) def _calc_dtype(self, space, l_dtype, r_dtype, out, casting, From noreply at buildbot.pypy.org Wed Sep 30 07:22:39 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 07:22:39 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: unskip order tests Message-ID: <20150930052239.2906C1C1E49@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79901:c32b25d8139f Date: 2015-09-30 08:22 +0300 http://bitbucket.org/pypy/pypy/changeset/c32b25d8139f/ Log: unskip order tests diff --git a/_pytest/core.py b/_pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -175,7 +175,7 @@ continue try: plugin = ep.load() - except DistributionNotFound: + except (DistributionNotFound, ImportError): continue self._plugin_distinfo.append((ep.dist, plugin)) self.register(plugin, name=name) diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -535,10 +535,10 @@ assert (b == a).all() b = a.copy(order='A') assert (b == a).all() - import sys - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.copy, order='F') - raises(NotImplementedError, a.copy, order=True) + b = a.copy(order='F') + assert (b == a).all() + b = a.copy(order=True) + assert (b == a).all() def test_iterator_init(self): from numpy import array @@ -919,9 +919,8 @@ assert a.reshape((0,), order='A').shape == (0,) raises(TypeError, a.reshape, (0,), badarg="C") raises(ValueError, a.reshape, (0,), order="K") - import sys - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.reshape, (0,), order='F') + b = a.reshape((0,), order='F') + assert b.shape == (0,) def test_slice_reshape(self): from numpy import zeros, arange @@ -2665,11 +2664,11 @@ assert a[1][2][1] == 15 def test_create_order(self): - import sys, numpy as np + import numpy as np for order in [False, True, 'C', 'F']: a = np.empty((2, 3), float, order=order) assert a.shape == (2, 3) - if order in [True, 'F'] and '__pypy__' not in sys.builtin_module_names: + if order in [True, 'F']: assert a.flags['F'] assert not a.flags['C'] else: @@ -3566,10 +3565,7 @@ assert a.tostring(order) == '\x01\x02\x03\x04' import sys for order in (True, 'F'): - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.tostring, order) - else: - assert a.tostring(order) == '\x01\x03\x02\x04' + assert a.tostring(order) == '\x01\x03\x02\x04' assert array(2.2-1.1j, dtype='>c16').tostring() == \ '@\x01\x99\x99\x99\x99\x99\x9a\xbf\xf1\x99\x99\x99\x99\x99\x9a' assert array(2.2-1.1j, dtype=' Author: Richard Plangger Branch: vecopt-merge Changeset: r79902:3e5ea9adeb03 Date: 2015-09-30 09:10 +0200 http://bitbucket.org/pypy/pypy/changeset/3e5ea9adeb03/ Log: partial test fixes in backend directory diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -135,6 +135,7 @@ MODEL_X86: ['floats', 'singlefloats', 'longlong'], MODEL_X86_NO_SSE2: ['longlong'], MODEL_X86_64: ['floats', 'singlefloats'], + MODEL_X86_64_SSE4: ['floats', 'singlefloats'], MODEL_ARM: ['floats', 'singlefloats', 'longlong'], MODEL_PPC_64: [], # we don't even have PPC directory, so no }[backend_name] 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 @@ -144,6 +144,7 @@ descr4 = get_array_descr(c0, A4) descr5 = get_array_descr(c0, A5) descr6 = get_array_descr(c0, A6) + import pdb; pdb.set_trace() assert isinstance(descr1, ArrayDescr) assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char)) assert descr1.flag == FLAG_UNSIGNED diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -23,9 +23,8 @@ from rpython.jit.codewriter import longlong from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr, - ConstFloat, INT, REF, FLOAT, VECTOR, TargetToken) + ConstFloat, INT, REF, FLOAT, VECTOR, TargetToken, AbstractFailDescr) from rpython.jit.metainterp.resoperation import rop, ResOperation -from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.metainterp.resume import AccumInfo from rpython.rlib import rgc from rpython.rlib.objectmodel import we_are_translated @@ -320,8 +319,10 @@ def locs_for_fail(self, guard_op): faillocs = [self.loc(arg) for arg in guard_op.getfailargs()] descr = guard_op.getdescr() - assert isinstance(descr, ResumeGuardDescr) - if descr and descr.rd_accum_list: + if not descr: + return faillocs + assert isinstance(descr, AbstractFailDescr) + if descr.rd_accum_list: accuminfo = descr.rd_accum_list while accuminfo: accuminfo.vector_loc = faillocs[accuminfo.getpos_in_failargs()] From noreply at buildbot.pypy.org Wed Sep 30 09:26:38 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 30 Sep 2015 09:26:38 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: fixed test_parser tests (overwrote update_memo) Message-ID: <20150930072638.CC2581C1311@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79903:b76456a0884f Date: 2015-09-30 09:21 +0200 http://bitbucket.org/pypy/pypy/changeset/b76456a0884f/ Log: fixed test_parser tests (overwrote update_memo) diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -366,7 +366,7 @@ Internally you will see the same variable names as in the trace as string. """ - regex = re.compile("[prif](\d+)") + regex = re.compile("[prifv](\d+)") match = regex.match(name) if match: counter = int(match.group(1)) diff --git a/rpython/tool/jitlogparser/parser.py b/rpython/tool/jitlogparser/parser.py --- a/rpython/tool/jitlogparser/parser.py +++ b/rpython/tool/jitlogparser/parser.py @@ -164,7 +164,8 @@ return self.Op(intern(opname[opnum].lower()), args, None, descr, fail_args) - + def update_memo(self, val, name): + pass class NonCodeError(Exception): pass From noreply at buildbot.pypy.org Wed Sep 30 09:26:40 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 30 Sep 2015 09:26:40 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: fixed tests that use the oparser_model instead of the real impl Message-ID: <20150930072640.DCA391C1311@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79904:eb5e01de1f93 Date: 2015-09-30 09:26 +0200 http://bitbucket.org/pypy/pypy/changeset/eb5e01de1f93/ Log: fixed tests that use the oparser_model instead of the real impl diff --git a/rpython/jit/tool/oparser_model.py b/rpython/jit/tool/oparser_model.py --- a/rpython/jit/tool/oparser_model.py +++ b/rpython/jit/tool/oparser_model.py @@ -79,19 +79,28 @@ type = 'V' class Const(object): + bytesize = 8 + signed = True def __init__(self, value=None): self.value = value def _get_str(self): return str(self.value) + def is_constant(self): + return True + class ConstInt(Const): + datatype = 'i' pass class ConstPtr(Const): + datatype = 'r' pass class ConstFloat(Const): + datatype = 'f' + signed = False pass @classmethod From noreply at buildbot.pypy.org Wed Sep 30 11:13:23 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 11:13:23 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: A branch to finally fix issues #126/#64 Message-ID: <20150930091323.2015D1C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2281:7a3319459076 Date: 2015-09-30 08:58 +0200 http://bitbucket.org/cffi/cffi/changeset/7a3319459076/ Log: A branch to finally fix issues #126/#64 From noreply at buildbot.pypy.org Wed Sep 30 11:13:25 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 11:13:25 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: in-progress: add qualifiers through model.py, cparser.py, and recompiler.py Message-ID: <20150930091325.2FFE31C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2282:ab9e37952de6 Date: 2015-09-30 11:00 +0200 http://bitbucket.org/cffi/cffi/changeset/ab9e37952de6/ Log: in-progress: add qualifiers through model.py, cparser.py, and recompiler.py diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -609,7 +609,7 @@ def make_accessor_locked(name): key = 'function ' + name if key in ffi._parser._declarations: - tp = ffi._parser._declarations[key] + tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) @@ -620,7 +620,7 @@ # key = 'variable ' + name if key in ffi._parser._declarations: - tp = ffi._parser._declarations[key] + tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) read_variable = backendlib.read_variable write_variable = backendlib.write_variable @@ -632,7 +632,7 @@ if not copied_enums: from . import model error = None - for key, tp in ffi._parser._declarations.items(): + for key, (tp, _) in ffi._parser._declarations.items(): if not isinstance(tp, model.EnumType): continue try: diff --git a/cffi/cparser.py b/cffi/cparser.py --- a/cffi/cparser.py +++ b/cffi/cparser.py @@ -192,6 +192,7 @@ if not decl.name: raise api.CDefError("typedef does not declare any name", decl) + quals = 0 if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and decl.type.type.names[-1] == '__dotdotdot__'): realtype = self._get_unknown_type(decl) @@ -202,8 +203,9 @@ decl.type.type.type.names == ['__dotdotdot__']): realtype = model.unknown_ptr_type(decl.name) else: - realtype = self._get_type(decl.type, name=decl.name) - self._declare('typedef ' + decl.name, realtype) + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name) + self._declare('typedef ' + decl.name, realtype, quals=quals) else: raise api.CDefError("unrecognized construct", decl) except api.FFIError as e: @@ -255,9 +257,9 @@ def _parse_decl(self, decl): node = decl.type if isinstance(node, pycparser.c_ast.FuncDecl): - tp = self._get_type(node, name=decl.name) + tp, quals = self._get_type_and_quals(node, name=decl.name) assert isinstance(tp, model.RawFunctionType) - tp = self._get_type_pointer(tp) + tp = self._get_type_pointer(tp, quals) self._declare('function ' + decl.name, tp) else: if isinstance(node, pycparser.c_ast.Struct): @@ -271,9 +273,10 @@ decl) # if decl.name: - tp = self._get_type(node, partial_length_ok=True) + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) if tp.is_raw_function: - tp = self._get_type_pointer(tp) + tp = self._get_type_pointer(tp, quals) self._declare('function ' + decl.name, tp) elif (tp.is_integer_type() and hasattr(decl, 'init') and @@ -287,10 +290,10 @@ _r_int_literal.match(decl.init.expr.value)): self._add_integer_constant(decl.name, '-' + decl.init.expr.value) - elif self._is_constant_globalvar(node): - self._declare('constant ' + decl.name, tp) + elif (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) else: - self._declare('variable ' + decl.name, tp) + self._declare('variable ' + decl.name, tp, quals=quals) def parse_type(self, cdecl): ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] @@ -298,40 +301,51 @@ exprnode = ast.ext[-1].type.args.params[0] if isinstance(exprnode, pycparser.c_ast.ID): raise api.CDefError("unknown identifier '%s'" % (exprnode.name,)) - return self._get_type(exprnode.type) + tp, quals = self._get_type_and_quals(exprnode.type) + return tp - def _declare(self, name, obj, included=False): + def _declare(self, name, obj, included=False, quals=0): if name in self._declarations: - if self._declarations[name] is obj: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: return if not self._override: raise api.FFIError( "multiple declarations of %s (for interactive usage, " "try cdef(xx, override=True))" % (name,)) assert '__dotdotdot__' not in name.split() - self._declarations[name] = obj + self._declarations[name] = (obj, quals) if included: self._included_declarations.add(obj) - def _get_type_pointer(self, type, const=False, declname=None): + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): if isinstance(type, model.RawFunctionType): return type.as_function_pointer() if (isinstance(type, model.StructOrUnionOrEnum) and type.name.startswith('$') and type.name[1:].isdigit() and type.forcename is None and declname is not None): - return model.NamedPointerType(type, declname) - if const: - return model.ConstPointerType(type) - return model.PointerType(type) + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) - def _get_type(self, typenode, name=None, partial_length_ok=False): + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False): # first, dereference typedefs, if we have it already parsed, we're good if (isinstance(typenode, pycparser.c_ast.TypeDecl) and isinstance(typenode.type, pycparser.c_ast.IdentifierType) and len(typenode.type.names) == 1 and ('typedef ' + typenode.type.names[0]) in self._declarations): - type = self._declarations['typedef ' + typenode.type.names[0]] - return type + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals # if isinstance(typenode, pycparser.c_ast.ArrayDecl): # array type @@ -340,18 +354,19 @@ else: length = self._parse_constant( typenode.dim, partial_length_ok=partial_length_ok) - tp = self._get_type(typenode.type, + tp, quals = self._get_type_and_quals(typenode.type, partial_length_ok=partial_length_ok) - return model.ArrayType(tp, length) + return model.ArrayType(tp, length), quals # if isinstance(typenode, pycparser.c_ast.PtrDecl): # pointer type - const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl) - and 'const' in typenode.type.quals) - return self._get_type_pointer(self._get_type(typenode.type), const, - declname=name) + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals # if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) type = typenode.type if isinstance(type, pycparser.c_ast.IdentifierType): # assume a primitive type. get it from .names, but reduce @@ -379,35 +394,38 @@ names = newnames + names ident = ' '.join(names) if ident == 'void': - return model.void_type + return model.void_type, quals if ident == '__dotdotdot__': raise api.FFIError(':%d: bad usage of "..."' % typenode.coord.line) - return resolve_common_type(ident) + return resolve_common_type(ident), quals # if isinstance(type, pycparser.c_ast.Struct): # 'struct foobar' - return self._get_struct_union_enum_type('struct', type, name) + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals # if isinstance(type, pycparser.c_ast.Union): # 'union foobar' - return self._get_struct_union_enum_type('union', type, name) + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals # if isinstance(type, pycparser.c_ast.Enum): # 'enum foobar' - return self._get_struct_union_enum_type('enum', type, name) + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals # if isinstance(typenode, pycparser.c_ast.FuncDecl): # a function type - return self._parse_function_type(typenode, name) + return self._parse_function_type(typenode, name), 0 # # nested anonymous structs or unions end up here if isinstance(typenode, pycparser.c_ast.Struct): return self._get_struct_union_enum_type('struct', typenode, name, - nested=True) + nested=True), 0 if isinstance(typenode, pycparser.c_ast.Union): return self._get_struct_union_enum_type('union', typenode, name, - nested=True) + nested=True), 0 # raise api.FFIError(":%d: bad or unsupported type declaration" % typenode.coord.line) @@ -426,28 +444,21 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - args = [self._as_func_arg(self._get_type(argdeclnode.type)) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) for argdeclnode in params] if not ellipsis and args == [model.void_type]: args = [] - result = self._get_type(typenode.type) + result, quals = self._get_type_and_quals(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) - def _as_func_arg(self, type): + def _as_func_arg(self, type, quals): if isinstance(type, model.ArrayType): - return model.PointerType(type.item) + return model.PointerType(type.item, quals) elif isinstance(type, model.RawFunctionType): return type.as_function_pointer() else: return type - def _is_constant_globalvar(self, typenode): - if isinstance(typenode, pycparser.c_ast.PtrDecl): - return 'const' in typenode.quals - if isinstance(typenode, pycparser.c_ast.TypeDecl): - return 'const' in typenode.quals - return False - def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): # First, a level of caching on the exact 'type' node of the AST. # This is obscure, but needed because pycparser "unrolls" declarations @@ -486,7 +497,7 @@ else: explicit_name = name key = '%s %s' % (kind, name) - tp = self._declarations.get(key, None) + tp, _ = self._declarations.get(key, (None, None)) # if tp is None: if kind == 'struct': @@ -528,6 +539,7 @@ fldnames = [] fldtypes = [] fldbitsize = [] + fldquals = [] for decl in type.decls: if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and ''.join(decl.type.names) == '__dotdotdot__'): @@ -541,7 +553,8 @@ else: bitsize = self._parse_constant(decl.bitsize) self._partial_length = False - type = self._get_type(decl.type, partial_length_ok=True) + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) if self._partial_length: self._make_partial(tp, nested) if isinstance(type, model.StructType) and type.partial: @@ -549,9 +562,11 @@ fldnames.append(decl.name or '') fldtypes.append(type) fldbitsize.append(bitsize) + fldquals.append(fqual) tp.fldnames = tuple(fldnames) tp.fldtypes = tuple(fldtypes) tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) if fldbitsize != [-1] * len(fldbitsize): if isinstance(tp, model.StructType) and tp.partial: raise NotImplementedError("%s: using both bitfields and '...;'" @@ -632,14 +647,12 @@ return tp def include(self, other): - for name, tp in other._declarations.items(): + for name, (tp, quals) in other._declarations.items(): if name.startswith('anonymous $enum_$'): continue # fix for test_anonymous_enum_include kind = name.split(' ', 1)[0] - if kind in ('struct', 'union', 'enum', 'anonymous'): - self._declare(name, tp, included=True) - elif kind == 'typedef': - self._declare(name, tp, included=True) + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) for k, v in other._int_constants.items(): self._add_constants(k, v) diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -4,6 +4,18 @@ from .lock import allocate_lock +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_RESTRICT: + replace_with = ' restrict ' + replace_with.lstrip() + return replace_with + + class BaseTypeByIdentity(object): is_array_type = False is_raw_function = False @@ -225,16 +237,14 @@ class PointerType(BaseType): - _attrs_ = ('totype',) - _base_pattern = " *&" - _base_pattern_array = "(*&)" + _attrs_ = ('totype', 'quals') - def __init__(self, totype): + def __init__(self, totype, quals=0): self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") if totype.is_array_type: - extra = self._base_pattern_array - else: - extra = self._base_pattern + extra = "(%s)" % (extra.lstrip(),) self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) def build_backend_type(self, ffi, finishlist): @@ -243,10 +253,8 @@ voidp_type = PointerType(void_type) - -class ConstPointerType(PointerType): - _base_pattern = " const *&" - _base_pattern_array = "(const *&)" +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) const_voidp_type = ConstPointerType(void_type) @@ -254,8 +262,8 @@ class NamedPointerType(PointerType): _attrs_ = ('totype', 'name') - def __init__(self, totype, name): - PointerType.__init__(self, totype) + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) self.name = name self.c_name_with_marker = name + '&' @@ -315,11 +323,12 @@ partial = False packed = False - def __init__(self, name, fldnames, fldtypes, fldbitsize): + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): self.name = name self.fldnames = fldnames self.fldtypes = fldtypes self.fldbitsize = fldbitsize + self.fldquals = fldquals self.build_c_name_with_marker() def has_anonymous_struct_fields(self): @@ -331,14 +340,17 @@ return False def enumfields(self): - for name, type, bitsize in zip(self.fldnames, self.fldtypes, - self.fldbitsize): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): if name == '' and isinstance(type, StructOrUnion): # nested anonymous struct/union for result in type.enumfields(): yield result else: - yield (name, type, bitsize) + yield (name, type, bitsize, quals) def force_flatten(self): # force the struct or union to have a declaration that lists @@ -347,13 +359,16 @@ names = [] types = [] bitsizes = [] - for name, type, bitsize in self.enumfields(): + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): names.append(name) types.append(type) bitsizes.append(bitsize) + fldquals.append(quals) self.fldnames = tuple(names) self.fldtypes = tuple(types) self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) def get_cached_btype(self, ffi, finishlist, can_delay=False): BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -195,17 +195,16 @@ elif isinstance(tp, model.StructOrUnion): if tp.fldtypes is not None and ( tp not in self.ffi._parser._included_declarations): - for name1, tp1, _ in tp.enumfields(): + for name1, tp1, _, _ in tp.enumfields(): self._do_collect_type(self._field_type(tp, name1, tp1)) else: for _, x in tp._get_items(): self._do_collect_type(x) - def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) - def _generate(self, step_name): - for name, tp in self._get_declarations(): + lst = self.ffi._parser._declarations.items() + lst.sort() + for name, (tp, quals) in lst: kind, realname = name.split(' ', 1) try: method = getattr(self, '_generate_cpy_%s_%s' % (kind, @@ -214,6 +213,7 @@ raise ffiplatform.VerificationError( "not implemented in recompile(): %r" % name) try: + self._current_quals = quals method(tp, realname) except Exception as e: model.attach_exception_info(e, name) @@ -774,7 +774,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): try: if ftype.is_integer_type() or fbitsize >= 0: # accept all integers, but complain on float or double @@ -788,8 +788,9 @@ and (ftype.length is None or ftype.length == '...')): ftype = ftype.item fname = fname + '[0]' + tmp = model.qualify(fqual, '*tmp') prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name(tmp, 'field %r'%fname), fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') @@ -823,7 +824,7 @@ c_fields = [] if reason_for_not_expanding is None: enumfields = list(tp.enumfields()) - for fldname, fldtype, fbitsize in enumfields: + for fldname, fldtype, fbitsize, fqual in enumfields: fldtype = self._field_type(tp, fldname, fldtype) # cname is None for _add_missing_struct_unions() only op = OP_NOOP @@ -1085,7 +1086,9 @@ # if 'tp' were a function type, but that is not possible here. # (If 'tp' is a function _pointer_ type, then casts from "fn_t # **" to "void *" are again no-ops, as far as I can tell.) - prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,))) + decl = '*_cffi_var_%s(void)' % (name,) + decl = model.qualify(self._current_quals, decl) + prnt('static ' + tp.get_c_name(decl)) prnt('{') prnt(' return %s(%s);' % (ampersand, name)) prnt('}') diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -197,7 +197,10 @@ return library def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst def _generate(self, step_name): for name, tp in self._get_declarations(): @@ -468,7 +471,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double @@ -488,7 +491,7 @@ prnt(' static Py_ssize_t nums[] = {') prnt(' sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now prnt(' offsetof(%s, %s),' % (cname, fname)) @@ -552,7 +555,7 @@ check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[1], ffi.alignof(BStruct), "wrong total alignment") i = 2 - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now check(layout[i], ffi.offsetof(BStruct, fname), diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -87,7 +87,10 @@ return library def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst def _generate(self, step_name): for name, tp in self._get_declarations(): @@ -260,7 +263,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double @@ -280,7 +283,7 @@ prnt(' static intptr_t nums[] = {') prnt(' sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now prnt(' offsetof(%s, %s),' % (cname, fname)) @@ -342,7 +345,7 @@ check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[1], ffi.alignof(BStruct), "wrong total alignment") i = 2 - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now check(layout[i], ffi.offsetof(BStruct, fname), diff --git a/testing/cffi0/test_model.py b/testing/cffi0/test_model.py --- a/testing/cffi0/test_model.py +++ b/testing/cffi0/test_model.py @@ -57,6 +57,11 @@ assert ptr_type.get_c_name("") == "int(const *)[5]" assert ptr_type.get_c_name("*x") == "int(const * *x)[5]" +def test_qual_pointer_type(): + ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT) + assert ptr_type.get_c_name("") == "long long restrict *" + assert const_voidp_type.get_c_name("") == "void const *" + def test_unknown_pointer_type(): ptr_type = unknown_ptr_type("foo_p") assert ptr_type.get_c_name("") == "foo_p" diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py --- a/testing/cffi0/test_parsing.py +++ b/testing/cffi0/test_parsing.py @@ -307,7 +307,6 @@ ffi.cdef("void f(WPARAM);") def test__is_constant_globalvar(): - from cffi.cparser import Parser, _get_parser for input, expected_output in [ ("int a;", False), ("const int a;", True), @@ -324,11 +323,23 @@ ("int a[5][6];", False), ("const int a[5][6];", False), ]: - p = Parser() - ast = _get_parser().parse(input) - decl = ast.children()[0][1] - node = decl.type - assert p._is_constant_globalvar(node) == expected_output + ffi = FFI() + ffi.cdef(input) + declarations = ffi._parser._declarations + assert ('constant a' in declarations) == expected_output + assert ('variable a' in declarations) == (not expected_output) + +def test_restrict(): + from cffi import model + for input, expected_output in [ + ("int a;", False), + ("restrict int a;", True), + ("int *a;", False), + ]: + ffi = FFI() + ffi.cdef(input) + tp, quals = ffi._parser._declarations['variable a'] + assert bool(quals & model.Q_RESTRICT) == expected_output def test_enum(): ffi = FFI() diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -1922,7 +1922,7 @@ assert repr(ffi.typeof(lib.a)) == "" def test_bug_const_char_ptr_array_2(): - ffi = FFI_warnings_not_error() # ignore warnings + ffi = FFI() ffi.cdef("""const int a[];""") lib = ffi.verify("""const int a[5];""") assert repr(ffi.typeof(lib.a)) == "" From noreply at buildbot.pypy.org Wed Sep 30 11:33:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 11:33:36 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: Tests and fixes for "const" fields Message-ID: <20150930093336.241091C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2283:f8c4c25618be Date: 2015-09-30 11:34 +0200 http://bitbucket.org/cffi/cffi/changeset/f8c4c25618be/ Log: Tests and fixes for "const" fields diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -20,7 +20,7 @@ is_array_type = False is_raw_function = False - def get_c_name(self, replace_with='', context='a C file'): + def get_c_name(self, replace_with='', context='a C file', quals=0): result = self.c_name_with_marker assert result.count('&') == 1 # some logic duplication with ffi.getctype()... :-( @@ -30,6 +30,7 @@ replace_with = '(%s)' % replace_with elif not replace_with[0] in '[(': replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) result = result.replace('&', replace_with) if '$' in result: from .ffiplatform import VerificationError diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -788,9 +788,9 @@ and (ftype.length is None or ftype.length == '...')): ftype = ftype.item fname = fname + '[0]' - tmp = model.qualify(fqual, '*tmp') prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name(tmp, 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') @@ -1087,8 +1087,7 @@ # (If 'tp' is a function _pointer_ type, then casts from "fn_t # **" to "void *" are again no-ops, as far as I can tell.) decl = '*_cffi_var_%s(void)' % (name,) - decl = model.qualify(self._current_quals, decl) - prnt('static ' + tp.get_c_name(decl)) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) prnt('{') prnt(' return %s(%s);' % (ampersand, name)) prnt('}') diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -1191,3 +1191,43 @@ py.test.raises(ffi.error, getattr, lib, 'my_value') e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50) assert str(e.value) == "global variable 'my_value' is at address NULL" + +def test_const_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a; void *const b; };""") + lib = verify(ffi, 'test_const_fields', """ + struct foo_s { const int a; void *const b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int") + assert foo_s.fields[1][0] == 'b' + assert foo_s.fields[1][1].type is ffi.typeof("void *") + +def test_restrict_fields(): + if sys.platform == 'win32': + py.test.skip("'__restrict__' probably not recognized") + ffi = FFI() + ffi.cdef("""struct foo_s { void * restrict b; };""") + lib = verify(ffi, 'test_const_fields', """ + struct foo_s { void * __restrict__ b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'b' + assert foo_s.fields[0][1].type is ffi.typeof("void *") + +def test_const_array_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[4]; };""") + lib = verify(ffi, 'test_const_array_fields', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[4]") + +def test_const_array_fields_varlength(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[]; ...; };""") + lib = verify(ffi, 'test_const_array_fields_varlength', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[]") From noreply at buildbot.pypy.org Wed Sep 30 11:48:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 11:48:36 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: Add more passing tests Message-ID: <20150930094836.309D61C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2284:524f9b024b0e Date: 2015-09-30 11:49 +0200 http://bitbucket.org/cffi/cffi/changeset/524f9b024b0e/ Log: Add more passing tests diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -1231,3 +1231,42 @@ foo_s = ffi.typeof("struct foo_s") assert foo_s.fields[0][0] == 'a' assert foo_s.fields[0][1].type is ffi.typeof("int[]") + +def test_const_array_fields_unknownlength(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[...]; ...; };""") + lib = verify(ffi, 'test_const_array_fields_unknownlength', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[4]") + +def test_const_function_args(): + ffi = FFI() + ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""") + lib = verify(ffi, 'test_const_function_args', """ + int foobar(const int a, const int *b, const int c[]) { + return a + *b + *c; + } + """) + assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142 + +def test_const_function_type_args(): + ffi = FFI() + ffi.cdef("""int (*foobar)(const int a, const int *b, const int c[]);""") + lib = verify(ffi, 'test_const_function_type_args', """ + int (*foobar)(const int a, const int *b, const int c[]); + """) + t = ffi.typeof(lib.foobar) + assert t.args[0] is ffi.typeof("int") + assert t.args[1] is ffi.typeof("int *") + assert t.args[2] is ffi.typeof("int *") + +def test_const_constant(): + ffi = FFI() + ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""") + lib = verify(ffi, 'test_const_constant', """ + struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 }; + """) + assert lib.myfoo.x == 40 + assert lib.myfoo.y == 2 From noreply at buildbot.pypy.org Wed Sep 30 11:52:10 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 11:52:10 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: Fix the verify() for const fields too, because it's very easy Message-ID: <20150930095210.178BF1C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2285:960b1aaf63ca Date: 2015-09-30 11:53 +0200 http://bitbucket.org/cffi/cffi/changeset/960b1aaf63ca/ Log: Fix the verify() for const fields too, because it's very easy diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -480,7 +480,8 @@ # only accept exactly the type declared. try: prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -272,7 +272,8 @@ # only accept exactly the type declared. try: prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -2247,3 +2247,13 @@ e = py.test.raises(VerificationError, ffi.verify, "") assert str(e.value) == ("feature not supported with ffi.verify(), but only " "with ffi.set_source(): 'typedef unsigned long... t1'") + +def test_const_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a; void *const b; };""") + ffi.verify("""struct foo_s { const int a; void *const b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int") + assert foo_s.fields[1][0] == 'b' + assert foo_s.fields[1][1].type is ffi.typeof("void *") From noreply at buildbot.pypy.org Wed Sep 30 12:08:07 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:08:07 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: fixes Message-ID: <20150930100807.8D4AD1C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2286:4ef1d72e9b05 Date: 2015-09-30 12:00 +0200 http://bitbucket.org/cffi/cffi/changeset/4ef1d72e9b05/ Log: fixes diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -203,8 +203,7 @@ def _generate(self, step_name): lst = self.ffi._parser._declarations.items() - lst.sort() - for name, (tp, quals) in lst: + for name, (tp, quals) in sorted(lst): kind, realname = name.split(' ', 1) try: method = getattr(self, '_generate_cpy_%s_%s' % (kind, diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -1208,7 +1208,7 @@ py.test.skip("'__restrict__' probably not recognized") ffi = FFI() ffi.cdef("""struct foo_s { void * restrict b; };""") - lib = verify(ffi, 'test_const_fields', """ + lib = verify(ffi, 'test_restrict_fields', """ struct foo_s { void * __restrict__ b; };""") foo_s = ffi.typeof("struct foo_s") assert foo_s.fields[0][0] == 'b' @@ -1270,3 +1270,13 @@ """) assert lib.myfoo.x == 40 assert lib.myfoo.y == 2 + +def test_const_via_typedef(): + ffi = FFI() + ffi.cdef("""typedef const int const_t; const_t aaa;""") + lib = verify(ffi, 'test_const_via_typedef', """ + typedef const int const_t; + #define aaa 42 + """) + assert lib.aaa == 42 + py.test.raises(AttributeError, "lib.aaa = 43") From noreply at buildbot.pypy.org Wed Sep 30 12:08:09 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:08:09 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: Seems that "__restrict" is recognized in all gcc modes I could try, Message-ID: <20150930100809.8A0171C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2287:f50320b732db Date: 2015-09-30 12:08 +0200 http://bitbucket.org/cffi/cffi/changeset/f50320b732db/ Log: Seems that "__restrict" is recognized in all gcc modes I could try, and it should also be recognized on MSVC diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -12,7 +12,7 @@ if quals & Q_CONST: replace_with = ' const ' + replace_with.lstrip() if quals & Q_RESTRICT: - replace_with = ' restrict ' + replace_with.lstrip() + replace_with = ' __restrict ' + replace_with.lstrip() return replace_with From noreply at buildbot.pypy.org Wed Sep 30 12:43:41 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:43:41 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: Documentation Message-ID: <20150930104341.E44A51C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2288:32ca56181815 Date: 2015-09-30 12:25 +0200 http://bitbucket.org/cffi/cffi/changeset/32ca56181815/ Log: Documentation diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -232,6 +232,15 @@ ``TCHAR`` and friends where hard-coded as unicode, but ``UNICODE`` was, inconsistently, not defined by default.) +Note that you can use the type-qualifiers ``const`` and ``restrict`` +(but not ``__restrict`` or ``__restrict__``) in the ``cdef()``, but +this has no effect on the cdata objects that you get at run-time (they +are never ``const``). The effect is limited to knowing if a global +variable is meant to be a constant or not. Also, *new in version +1.3:* when using ``set_source()`` or ``verify()``, these two +qualifiers are copied from the cdef to the generated C code; this +fixes warnings by the C compiler. + .. _loading-libraries: diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst --- a/doc/source/whatsnew.rst +++ b/doc/source/whatsnew.rst @@ -13,6 +13,12 @@ * Issue #217: fix possible unaligned pointer manipulation, which crash on some architectures (64-bit, non-x86). +* Issues #64 and #126: when using ``set_source()`` or ``verify()``, + the ``const`` and ``restrict`` keywords are copied from the cdef + to the generated C code; this fixes warnings by the C compiler. + It also fixes corner cases like ``typedef const int T; T a;`` + which would previously not consider ``a`` as a constant. + v1.2.1 ====== From noreply at buildbot.pypy.org Wed Sep 30 12:43:43 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:43:43 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: add a passing test Message-ID: <20150930104343.ECA2B1C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2289:5f8686315e12 Date: 2015-09-30 12:33 +0200 http://bitbucket.org/cffi/cffi/changeset/5f8686315e12/ Log: add a passing test diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py --- a/testing/cffi0/test_parsing.py +++ b/testing/cffi0/test_parsing.py @@ -341,6 +341,19 @@ tp, quals = ffi._parser._declarations['variable a'] assert bool(quals & model.Q_RESTRICT) == expected_output +def test_different_const_funcptr_types(): + lst = [] + for input in [ + "int(*)(int *a)", + "int(*)(int const *a)", + "int(*)(int * const a)", + "int(*)(int const a[])"]: + ffi = FFI(backend=FakeBackend()) + lst.append(ffi._parser.parse_type(input)) + assert lst[0] != lst[1] + assert lst[0] == lst[2] + assert lst[1] == lst[3] + def test_enum(): ffi = FFI() ffi.cdef(""" From noreply at buildbot.pypy.org Wed Sep 30 12:43:45 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:43:45 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: A note Message-ID: <20150930104345.D51FF1C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2290:db28e5f548ff Date: 2015-09-30 12:37 +0200 http://bitbucket.org/cffi/cffi/changeset/db28e5f548ff/ Log: A note diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -12,6 +12,9 @@ if quals & Q_CONST: replace_with = ' const ' + replace_with.lstrip() if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) replace_with = ' __restrict ' + replace_with.lstrip() return replace_with From noreply at buildbot.pypy.org Wed Sep 30 12:43:47 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:43:47 +0200 (CEST) Subject: [pypy-commit] cffi qualtypes: ready for merge Message-ID: <20150930104347.BBB421C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: qualtypes Changeset: r2291:6423f915f968 Date: 2015-09-30 12:42 +0200 http://bitbucket.org/cffi/cffi/changeset/6423f915f968/ Log: ready for merge From noreply at buildbot.pypy.org Wed Sep 30 12:43:49 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 12:43:49 +0200 (CEST) Subject: [pypy-commit] cffi default: hg merge qualtypes Message-ID: <20150930104349.BB31B1C1193@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2292:f0d15960e353 Date: 2015-09-30 12:44 +0200 http://bitbucket.org/cffi/cffi/changeset/f0d15960e353/ Log: hg merge qualtypes Fixes a long-standing problem with producing warnings-free code if the real C header uses "const" or "restrict". See issues #64 and #126. diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -609,7 +609,7 @@ def make_accessor_locked(name): key = 'function ' + name if key in ffi._parser._declarations: - tp = ffi._parser._declarations[key] + tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) @@ -620,7 +620,7 @@ # key = 'variable ' + name if key in ffi._parser._declarations: - tp = ffi._parser._declarations[key] + tp, _ = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) read_variable = backendlib.read_variable write_variable = backendlib.write_variable @@ -632,7 +632,7 @@ if not copied_enums: from . import model error = None - for key, tp in ffi._parser._declarations.items(): + for key, (tp, _) in ffi._parser._declarations.items(): if not isinstance(tp, model.EnumType): continue try: diff --git a/cffi/cparser.py b/cffi/cparser.py --- a/cffi/cparser.py +++ b/cffi/cparser.py @@ -192,6 +192,7 @@ if not decl.name: raise api.CDefError("typedef does not declare any name", decl) + quals = 0 if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and decl.type.type.names[-1] == '__dotdotdot__'): realtype = self._get_unknown_type(decl) @@ -202,8 +203,9 @@ decl.type.type.type.names == ['__dotdotdot__']): realtype = model.unknown_ptr_type(decl.name) else: - realtype = self._get_type(decl.type, name=decl.name) - self._declare('typedef ' + decl.name, realtype) + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name) + self._declare('typedef ' + decl.name, realtype, quals=quals) else: raise api.CDefError("unrecognized construct", decl) except api.FFIError as e: @@ -255,9 +257,9 @@ def _parse_decl(self, decl): node = decl.type if isinstance(node, pycparser.c_ast.FuncDecl): - tp = self._get_type(node, name=decl.name) + tp, quals = self._get_type_and_quals(node, name=decl.name) assert isinstance(tp, model.RawFunctionType) - tp = self._get_type_pointer(tp) + tp = self._get_type_pointer(tp, quals) self._declare('function ' + decl.name, tp) else: if isinstance(node, pycparser.c_ast.Struct): @@ -271,9 +273,10 @@ decl) # if decl.name: - tp = self._get_type(node, partial_length_ok=True) + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) if tp.is_raw_function: - tp = self._get_type_pointer(tp) + tp = self._get_type_pointer(tp, quals) self._declare('function ' + decl.name, tp) elif (tp.is_integer_type() and hasattr(decl, 'init') and @@ -287,10 +290,10 @@ _r_int_literal.match(decl.init.expr.value)): self._add_integer_constant(decl.name, '-' + decl.init.expr.value) - elif self._is_constant_globalvar(node): - self._declare('constant ' + decl.name, tp) + elif (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) else: - self._declare('variable ' + decl.name, tp) + self._declare('variable ' + decl.name, tp, quals=quals) def parse_type(self, cdecl): ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] @@ -298,40 +301,51 @@ exprnode = ast.ext[-1].type.args.params[0] if isinstance(exprnode, pycparser.c_ast.ID): raise api.CDefError("unknown identifier '%s'" % (exprnode.name,)) - return self._get_type(exprnode.type) + tp, quals = self._get_type_and_quals(exprnode.type) + return tp - def _declare(self, name, obj, included=False): + def _declare(self, name, obj, included=False, quals=0): if name in self._declarations: - if self._declarations[name] is obj: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: return if not self._override: raise api.FFIError( "multiple declarations of %s (for interactive usage, " "try cdef(xx, override=True))" % (name,)) assert '__dotdotdot__' not in name.split() - self._declarations[name] = obj + self._declarations[name] = (obj, quals) if included: self._included_declarations.add(obj) - def _get_type_pointer(self, type, const=False, declname=None): + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): if isinstance(type, model.RawFunctionType): return type.as_function_pointer() if (isinstance(type, model.StructOrUnionOrEnum) and type.name.startswith('$') and type.name[1:].isdigit() and type.forcename is None and declname is not None): - return model.NamedPointerType(type, declname) - if const: - return model.ConstPointerType(type) - return model.PointerType(type) + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) - def _get_type(self, typenode, name=None, partial_length_ok=False): + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False): # first, dereference typedefs, if we have it already parsed, we're good if (isinstance(typenode, pycparser.c_ast.TypeDecl) and isinstance(typenode.type, pycparser.c_ast.IdentifierType) and len(typenode.type.names) == 1 and ('typedef ' + typenode.type.names[0]) in self._declarations): - type = self._declarations['typedef ' + typenode.type.names[0]] - return type + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals # if isinstance(typenode, pycparser.c_ast.ArrayDecl): # array type @@ -340,18 +354,19 @@ else: length = self._parse_constant( typenode.dim, partial_length_ok=partial_length_ok) - tp = self._get_type(typenode.type, + tp, quals = self._get_type_and_quals(typenode.type, partial_length_ok=partial_length_ok) - return model.ArrayType(tp, length) + return model.ArrayType(tp, length), quals # if isinstance(typenode, pycparser.c_ast.PtrDecl): # pointer type - const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl) - and 'const' in typenode.type.quals) - return self._get_type_pointer(self._get_type(typenode.type), const, - declname=name) + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals # if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) type = typenode.type if isinstance(type, pycparser.c_ast.IdentifierType): # assume a primitive type. get it from .names, but reduce @@ -379,35 +394,38 @@ names = newnames + names ident = ' '.join(names) if ident == 'void': - return model.void_type + return model.void_type, quals if ident == '__dotdotdot__': raise api.FFIError(':%d: bad usage of "..."' % typenode.coord.line) - return resolve_common_type(ident) + return resolve_common_type(ident), quals # if isinstance(type, pycparser.c_ast.Struct): # 'struct foobar' - return self._get_struct_union_enum_type('struct', type, name) + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals # if isinstance(type, pycparser.c_ast.Union): # 'union foobar' - return self._get_struct_union_enum_type('union', type, name) + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals # if isinstance(type, pycparser.c_ast.Enum): # 'enum foobar' - return self._get_struct_union_enum_type('enum', type, name) + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals # if isinstance(typenode, pycparser.c_ast.FuncDecl): # a function type - return self._parse_function_type(typenode, name) + return self._parse_function_type(typenode, name), 0 # # nested anonymous structs or unions end up here if isinstance(typenode, pycparser.c_ast.Struct): return self._get_struct_union_enum_type('struct', typenode, name, - nested=True) + nested=True), 0 if isinstance(typenode, pycparser.c_ast.Union): return self._get_struct_union_enum_type('union', typenode, name, - nested=True) + nested=True), 0 # raise api.FFIError(":%d: bad or unsupported type declaration" % typenode.coord.line) @@ -426,28 +444,21 @@ raise api.CDefError( "%s: a function with only '(...)' as argument" " is not correct C" % (funcname or 'in expression')) - args = [self._as_func_arg(self._get_type(argdeclnode.type)) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) for argdeclnode in params] if not ellipsis and args == [model.void_type]: args = [] - result = self._get_type(typenode.type) + result, quals = self._get_type_and_quals(typenode.type) return model.RawFunctionType(tuple(args), result, ellipsis) - def _as_func_arg(self, type): + def _as_func_arg(self, type, quals): if isinstance(type, model.ArrayType): - return model.PointerType(type.item) + return model.PointerType(type.item, quals) elif isinstance(type, model.RawFunctionType): return type.as_function_pointer() else: return type - def _is_constant_globalvar(self, typenode): - if isinstance(typenode, pycparser.c_ast.PtrDecl): - return 'const' in typenode.quals - if isinstance(typenode, pycparser.c_ast.TypeDecl): - return 'const' in typenode.quals - return False - def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): # First, a level of caching on the exact 'type' node of the AST. # This is obscure, but needed because pycparser "unrolls" declarations @@ -486,7 +497,7 @@ else: explicit_name = name key = '%s %s' % (kind, name) - tp = self._declarations.get(key, None) + tp, _ = self._declarations.get(key, (None, None)) # if tp is None: if kind == 'struct': @@ -528,6 +539,7 @@ fldnames = [] fldtypes = [] fldbitsize = [] + fldquals = [] for decl in type.decls: if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and ''.join(decl.type.names) == '__dotdotdot__'): @@ -541,7 +553,8 @@ else: bitsize = self._parse_constant(decl.bitsize) self._partial_length = False - type = self._get_type(decl.type, partial_length_ok=True) + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) if self._partial_length: self._make_partial(tp, nested) if isinstance(type, model.StructType) and type.partial: @@ -549,9 +562,11 @@ fldnames.append(decl.name or '') fldtypes.append(type) fldbitsize.append(bitsize) + fldquals.append(fqual) tp.fldnames = tuple(fldnames) tp.fldtypes = tuple(fldtypes) tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) if fldbitsize != [-1] * len(fldbitsize): if isinstance(tp, model.StructType) and tp.partial: raise NotImplementedError("%s: using both bitfields and '...;'" @@ -632,14 +647,12 @@ return tp def include(self, other): - for name, tp in other._declarations.items(): + for name, (tp, quals) in other._declarations.items(): if name.startswith('anonymous $enum_$'): continue # fix for test_anonymous_enum_include kind = name.split(' ', 1)[0] - if kind in ('struct', 'union', 'enum', 'anonymous'): - self._declare(name, tp, included=True) - elif kind == 'typedef': - self._declare(name, tp, included=True) + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) for k, v in other._int_constants.items(): self._add_constants(k, v) diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -4,11 +4,26 @@ from .lock import allocate_lock +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + class BaseTypeByIdentity(object): is_array_type = False is_raw_function = False - def get_c_name(self, replace_with='', context='a C file'): + def get_c_name(self, replace_with='', context='a C file', quals=0): result = self.c_name_with_marker assert result.count('&') == 1 # some logic duplication with ffi.getctype()... :-( @@ -18,6 +33,7 @@ replace_with = '(%s)' % replace_with elif not replace_with[0] in '[(': replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) result = result.replace('&', replace_with) if '$' in result: from .ffiplatform import VerificationError @@ -225,16 +241,14 @@ class PointerType(BaseType): - _attrs_ = ('totype',) - _base_pattern = " *&" - _base_pattern_array = "(*&)" + _attrs_ = ('totype', 'quals') - def __init__(self, totype): + def __init__(self, totype, quals=0): self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") if totype.is_array_type: - extra = self._base_pattern_array - else: - extra = self._base_pattern + extra = "(%s)" % (extra.lstrip(),) self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) def build_backend_type(self, ffi, finishlist): @@ -243,10 +257,8 @@ voidp_type = PointerType(void_type) - -class ConstPointerType(PointerType): - _base_pattern = " const *&" - _base_pattern_array = "(const *&)" +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) const_voidp_type = ConstPointerType(void_type) @@ -254,8 +266,8 @@ class NamedPointerType(PointerType): _attrs_ = ('totype', 'name') - def __init__(self, totype, name): - PointerType.__init__(self, totype) + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) self.name = name self.c_name_with_marker = name + '&' @@ -315,11 +327,12 @@ partial = False packed = False - def __init__(self, name, fldnames, fldtypes, fldbitsize): + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): self.name = name self.fldnames = fldnames self.fldtypes = fldtypes self.fldbitsize = fldbitsize + self.fldquals = fldquals self.build_c_name_with_marker() def has_anonymous_struct_fields(self): @@ -331,14 +344,17 @@ return False def enumfields(self): - for name, type, bitsize in zip(self.fldnames, self.fldtypes, - self.fldbitsize): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): if name == '' and isinstance(type, StructOrUnion): # nested anonymous struct/union for result in type.enumfields(): yield result else: - yield (name, type, bitsize) + yield (name, type, bitsize, quals) def force_flatten(self): # force the struct or union to have a declaration that lists @@ -347,13 +363,16 @@ names = [] types = [] bitsizes = [] - for name, type, bitsize in self.enumfields(): + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): names.append(name) types.append(type) bitsizes.append(bitsize) + fldquals.append(quals) self.fldnames = tuple(names) self.fldtypes = tuple(types) self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) def get_cached_btype(self, ffi, finishlist, can_delay=False): BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -195,17 +195,15 @@ elif isinstance(tp, model.StructOrUnion): if tp.fldtypes is not None and ( tp not in self.ffi._parser._included_declarations): - for name1, tp1, _ in tp.enumfields(): + for name1, tp1, _, _ in tp.enumfields(): self._do_collect_type(self._field_type(tp, name1, tp1)) else: for _, x in tp._get_items(): self._do_collect_type(x) - def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) - def _generate(self, step_name): - for name, tp in self._get_declarations(): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): kind, realname = name.split(' ', 1) try: method = getattr(self, '_generate_cpy_%s_%s' % (kind, @@ -214,6 +212,7 @@ raise ffiplatform.VerificationError( "not implemented in recompile(): %r" % name) try: + self._current_quals = quals method(tp, realname) except Exception as e: model.attach_exception_info(e, name) @@ -774,7 +773,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): try: if ftype.is_integer_type() or fbitsize >= 0: # accept all integers, but complain on float or double @@ -789,7 +788,8 @@ ftype = ftype.item fname = fname + '[0]' prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') @@ -823,7 +823,7 @@ c_fields = [] if reason_for_not_expanding is None: enumfields = list(tp.enumfields()) - for fldname, fldtype, fbitsize in enumfields: + for fldname, fldtype, fbitsize, fqual in enumfields: fldtype = self._field_type(tp, fldname, fldtype) # cname is None for _add_missing_struct_unions() only op = OP_NOOP @@ -1085,7 +1085,8 @@ # if 'tp' were a function type, but that is not possible here. # (If 'tp' is a function _pointer_ type, then casts from "fn_t # **" to "void *" are again no-ops, as far as I can tell.) - prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,))) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) prnt('{') prnt(' return %s(%s);' % (ampersand, name)) prnt('}') diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -197,7 +197,10 @@ return library def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst def _generate(self, step_name): for name, tp in self._get_declarations(): @@ -468,7 +471,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double @@ -477,7 +480,8 @@ # only accept exactly the type declared. try: prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') @@ -488,7 +492,7 @@ prnt(' static Py_ssize_t nums[] = {') prnt(' sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now prnt(' offsetof(%s, %s),' % (cname, fname)) @@ -552,7 +556,7 @@ check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[1], ffi.alignof(BStruct), "wrong total alignment") i = 2 - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now check(layout[i], ffi.offsetof(BStruct, fname), diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -87,7 +87,10 @@ return library def _get_declarations(self): - return sorted(self.ffi._parser._declarations.items()) + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst def _generate(self, step_name): for name, tp in self._get_declarations(): @@ -260,7 +263,7 @@ prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double @@ -269,7 +272,8 @@ # only accept exactly the type declared. try: prnt(' { %s = &p->%s; (void)tmp; }' % ( - ftype.get_c_name('*tmp', 'field %r'%fname), fname)) + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) except ffiplatform.VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') @@ -280,7 +284,7 @@ prnt(' static intptr_t nums[] = {') prnt(' sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now prnt(' offsetof(%s, %s),' % (cname, fname)) @@ -342,7 +346,7 @@ check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[1], ffi.alignof(BStruct), "wrong total alignment") i = 2 - for fname, ftype, fbitsize in tp.enumfields(): + for fname, ftype, fbitsize, fqual in tp.enumfields(): if fbitsize >= 0: continue # xxx ignore fbitsize for now check(layout[i], ffi.offsetof(BStruct, fname), diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -232,6 +232,15 @@ ``TCHAR`` and friends where hard-coded as unicode, but ``UNICODE`` was, inconsistently, not defined by default.) +Note that you can use the type-qualifiers ``const`` and ``restrict`` +(but not ``__restrict`` or ``__restrict__``) in the ``cdef()``, but +this has no effect on the cdata objects that you get at run-time (they +are never ``const``). The effect is limited to knowing if a global +variable is meant to be a constant or not. Also, *new in version +1.3:* when using ``set_source()`` or ``verify()``, these two +qualifiers are copied from the cdef to the generated C code; this +fixes warnings by the C compiler. + .. _loading-libraries: diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst --- a/doc/source/whatsnew.rst +++ b/doc/source/whatsnew.rst @@ -13,6 +13,12 @@ * Issue #217: fix possible unaligned pointer manipulation, which crash on some architectures (64-bit, non-x86). +* Issues #64 and #126: when using ``set_source()`` or ``verify()``, + the ``const`` and ``restrict`` keywords are copied from the cdef + to the generated C code; this fixes warnings by the C compiler. + It also fixes corner cases like ``typedef const int T; T a;`` + which would previously not consider ``a`` as a constant. + v1.2.1 ====== diff --git a/testing/cffi0/test_model.py b/testing/cffi0/test_model.py --- a/testing/cffi0/test_model.py +++ b/testing/cffi0/test_model.py @@ -57,6 +57,11 @@ assert ptr_type.get_c_name("") == "int(const *)[5]" assert ptr_type.get_c_name("*x") == "int(const * *x)[5]" +def test_qual_pointer_type(): + ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT) + assert ptr_type.get_c_name("") == "long long restrict *" + assert const_voidp_type.get_c_name("") == "void const *" + def test_unknown_pointer_type(): ptr_type = unknown_ptr_type("foo_p") assert ptr_type.get_c_name("") == "foo_p" diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py --- a/testing/cffi0/test_parsing.py +++ b/testing/cffi0/test_parsing.py @@ -307,7 +307,6 @@ ffi.cdef("void f(WPARAM);") def test__is_constant_globalvar(): - from cffi.cparser import Parser, _get_parser for input, expected_output in [ ("int a;", False), ("const int a;", True), @@ -324,11 +323,36 @@ ("int a[5][6];", False), ("const int a[5][6];", False), ]: - p = Parser() - ast = _get_parser().parse(input) - decl = ast.children()[0][1] - node = decl.type - assert p._is_constant_globalvar(node) == expected_output + ffi = FFI() + ffi.cdef(input) + declarations = ffi._parser._declarations + assert ('constant a' in declarations) == expected_output + assert ('variable a' in declarations) == (not expected_output) + +def test_restrict(): + from cffi import model + for input, expected_output in [ + ("int a;", False), + ("restrict int a;", True), + ("int *a;", False), + ]: + ffi = FFI() + ffi.cdef(input) + tp, quals = ffi._parser._declarations['variable a'] + assert bool(quals & model.Q_RESTRICT) == expected_output + +def test_different_const_funcptr_types(): + lst = [] + for input in [ + "int(*)(int *a)", + "int(*)(int const *a)", + "int(*)(int * const a)", + "int(*)(int const a[])"]: + ffi = FFI(backend=FakeBackend()) + lst.append(ffi._parser.parse_type(input)) + assert lst[0] != lst[1] + assert lst[0] == lst[2] + assert lst[1] == lst[3] def test_enum(): ffi = FFI() diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -2247,3 +2247,13 @@ e = py.test.raises(VerificationError, ffi.verify, "") assert str(e.value) == ("feature not supported with ffi.verify(), but only " "with ffi.set_source(): 'typedef unsigned long... t1'") + +def test_const_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a; void *const b; };""") + ffi.verify("""struct foo_s { const int a; void *const b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int") + assert foo_s.fields[1][0] == 'b' + assert foo_s.fields[1][1].type is ffi.typeof("void *") diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -1191,3 +1191,92 @@ py.test.raises(ffi.error, getattr, lib, 'my_value') e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50) assert str(e.value) == "global variable 'my_value' is at address NULL" + +def test_const_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a; void *const b; };""") + lib = verify(ffi, 'test_const_fields', """ + struct foo_s { const int a; void *const b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int") + assert foo_s.fields[1][0] == 'b' + assert foo_s.fields[1][1].type is ffi.typeof("void *") + +def test_restrict_fields(): + if sys.platform == 'win32': + py.test.skip("'__restrict__' probably not recognized") + ffi = FFI() + ffi.cdef("""struct foo_s { void * restrict b; };""") + lib = verify(ffi, 'test_restrict_fields', """ + struct foo_s { void * __restrict__ b; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'b' + assert foo_s.fields[0][1].type is ffi.typeof("void *") + +def test_const_array_fields(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[4]; };""") + lib = verify(ffi, 'test_const_array_fields', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[4]") + +def test_const_array_fields_varlength(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[]; ...; };""") + lib = verify(ffi, 'test_const_array_fields_varlength', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[]") + +def test_const_array_fields_unknownlength(): + ffi = FFI() + ffi.cdef("""struct foo_s { const int a[...]; ...; };""") + lib = verify(ffi, 'test_const_array_fields_unknownlength', """ + struct foo_s { const int a[4]; };""") + foo_s = ffi.typeof("struct foo_s") + assert foo_s.fields[0][0] == 'a' + assert foo_s.fields[0][1].type is ffi.typeof("int[4]") + +def test_const_function_args(): + ffi = FFI() + ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""") + lib = verify(ffi, 'test_const_function_args', """ + int foobar(const int a, const int *b, const int c[]) { + return a + *b + *c; + } + """) + assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142 + +def test_const_function_type_args(): + ffi = FFI() + ffi.cdef("""int (*foobar)(const int a, const int *b, const int c[]);""") + lib = verify(ffi, 'test_const_function_type_args', """ + int (*foobar)(const int a, const int *b, const int c[]); + """) + t = ffi.typeof(lib.foobar) + assert t.args[0] is ffi.typeof("int") + assert t.args[1] is ffi.typeof("int *") + assert t.args[2] is ffi.typeof("int *") + +def test_const_constant(): + ffi = FFI() + ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""") + lib = verify(ffi, 'test_const_constant', """ + struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 }; + """) + assert lib.myfoo.x == 40 + assert lib.myfoo.y == 2 + +def test_const_via_typedef(): + ffi = FFI() + ffi.cdef("""typedef const int const_t; const_t aaa;""") + lib = verify(ffi, 'test_const_via_typedef', """ + typedef const int const_t; + #define aaa 42 + """) + assert lib.aaa == 42 + py.test.raises(AttributeError, "lib.aaa = 43") diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -1922,7 +1922,7 @@ assert repr(ffi.typeof(lib.a)) == "" def test_bug_const_char_ptr_array_2(): - ffi = FFI_warnings_not_error() # ignore warnings + ffi = FFI() ffi.cdef("""const int a[];""") lib = ffi.verify("""const int a[5];""") assert repr(ffi.typeof(lib.a)) == "" From noreply at buildbot.pypy.org Wed Sep 30 15:53:10 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 30 Sep 2015 15:53:10 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: forgot to cache the descr when concrete type is set, some minor changes reverted Message-ID: <20150930135310.AFEB71C21A4@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79905:190de8806c18 Date: 2015-09-30 15:31 +0200 http://bitbucket.org/pypy/pypy/changeset/190de8806c18/ Log: forgot to cache the descr when concrete type is set, some minor changes reverted diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -932,7 +932,6 @@ while regalloc.position() < len(operations) - 1: regalloc.next_instruction() i = regalloc.position() - self.position = i op = operations[i] self.mc.mark_op(op) opnum = op.getopnum() diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -180,13 +180,13 @@ gcmap = allocate_gcmap(self, frame_depth, JITFRAME_FIXED_SIZE) token = ArmGuardToken(self.cpu, gcmap, - descr, - failargs=op.getfailargs(), - fail_locs=arglocs, - offset=offset, - guard_opnum=op.getopnum(), - frame_depth=frame_depth, - fcond=fcond) + descr, + failargs=op.getfailargs(), + fail_locs=arglocs, + offset=offset, + guard_opnum=op.getopnum(), + frame_depth=frame_depth, + fcond=fcond) return token def _emit_guard(self, op, arglocs, is_guard_not_invalidated=False): @@ -199,6 +199,7 @@ pos = self.mc.currpos() token = self.build_guard_token(op, arglocs[0].value, arglocs[1:], pos, fcond) self.pending_guards.append(token) + assert token.guard_not_invalidated() == is_guard_not_invalidated # For all guards that are not GUARD_NOT_INVALIDATED we emit a # breakpoint to ensure the location is patched correctly. In the case # of GUARD_NOT_INVALIDATED we use just a NOP, because it is only 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 @@ -209,8 +209,7 @@ def is_array_of_primitives(self): kind = getkind(self.A.OF) return kind == 'float' or \ - kind == 'int' or \ - kind == '' + kind == 'int' def is_always_pure(self): return self._is_pure @@ -221,12 +220,6 @@ def __repr__(self): return 'ArrayDescr(%r)' % (self.OUTERA,) - def get_all_fielddescrs(self): - return self.all_interiorfielddescrs - - def __repr__(self): - return 'ArrayDescr(%r)' % (self.OUTERA,) - def is_array_of_pointers(self): return getkind(self.A.OF) == 'ref' @@ -1069,7 +1062,7 @@ def fail_guard(self, descr, saved_data=None): values = [] - for i,box in enumerate(self.current_op.getfailargs()): + for box in self.current_op.getfailargs(): if box is not None: value = self.env[box] else: @@ -1095,9 +1088,6 @@ argboxes = self.current_op.getarglist() self.do_renaming(argboxes, args) - def execute_guard_early_exit(self, descr): - pass - def _test_true(self, arg): if isinstance(arg, list): return all(arg) diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py --- a/rpython/jit/backend/llsupport/assembler.py +++ b/rpython/jit/backend/llsupport/assembler.py @@ -2,8 +2,8 @@ from rpython.jit.backend.llsupport.memcpy import memcpy_fn, memset_fn from rpython.jit.backend.llsupport.symbolic import WORD from rpython.jit.backend.llsupport.codemap import CodemapBuilder -from rpython.jit.metainterp.history import (INT, REF, FLOAT, VECTOR, - JitCellToken, ConstInt, AbstractFailDescr) +from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken, + ConstInt, AbstractFailDescr, VECTOR) from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.rlib import rgc from rpython.rlib.debug import (debug_start, debug_stop, have_debug_prints_for, 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 @@ -285,9 +285,6 @@ def get_item_size_in_bytes(self): return self.itemsize - def get_flag(self): - return self.flag - def is_array_of_structs(self): return self.flag == FLAG_STRUCT @@ -337,18 +334,16 @@ flag = get_type_flag(ARRAY_INSIDE.OF) is_pure = bool(ARRAY_INSIDE._immutable_field(None)) arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag, is_pure) + if ARRAY_INSIDE.OF is lltype.SingleFloat or \ + ARRAY_INSIDE.OF is lltype.Float: + # it would be better to set the flag as FLOAT_TYPE + # for single float -> leads to problems + arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag, is_pure, concrete_type='f') cache[ARRAY_OR_STRUCT] = arraydescr if isinstance(ARRAY_INSIDE.OF, lltype.Struct): descrs = heaptracker.all_interiorfielddescrs(gccache, ARRAY_INSIDE, get_field_descr=get_interiorfield_descr) arraydescr.all_interiorfielddescrs = descrs - concrete_type = '\x00' - if ARRAY_INSIDE.OF is lltype.SingleFloat or \ - ARRAY_INSIDE.OF is lltype.Float: - # it would be better to set the flag as FLOAT_TYPE - # for single float -> leads to problems - concrete_type = 'f' - arraydescr = ArrayDescr(basesize, itemsize, lendescr, flag, is_pure, concrete_type=concrete_type) if ARRAY_OR_STRUCT._gckind == 'gc': gccache.init_array_descr(ARRAY_OR_STRUCT, arraydescr) return arraydescr 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 @@ -1465,13 +1465,11 @@ assert kind == 'v' return lltype.nullptr(rclass.OBJECTPTR.TO) - def _prepare_resume_from_failure(self, opnum, deadframe, resumedescr): + def _prepare_resume_from_failure(self, opnum, deadframe): from rpython.jit.metainterp.resoperation import rop # if opnum == rop.GUARD_FUTURE_CONDITION: pass - elif opnum == rop.GUARD_EARLY_EXIT: - self.position = resumedescr.rd_frame_info_list.pc elif opnum == rop.GUARD_TRUE: # Produced directly by some goto_if_not_xxx() opcode that did not # jump, but which must now jump. The pc is just after the opcode. @@ -1644,7 +1642,7 @@ all_virtuals) current_exc = blackholeinterp._prepare_resume_from_failure( - resumedescr.guard_opnum, deadframe, resumedescr) + resumedescr.guard_opnum, deadframe) _run_forever(blackholeinterp, current_exc) resume_in_blackhole._dont_inline_ = True diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -19,13 +19,14 @@ ResumeDataDirectReader, AccumInfo) from rpython.jit.codewriter import heaptracker, longlong + def giveup(): from rpython.jit.metainterp.pyjitpl import SwitchToBlackhole raise SwitchToBlackhole(Counters.ABORT_BRIDGE) class CompileData(object): memo = None - + def forget_optimization_info(self): for arg in self.start_label.getarglist(): arg.set_forwarded(None) @@ -149,6 +150,7 @@ loop = TreeLoop(name_prefix + name) return loop + def make_jitcell_token(jitdriver_sd): jitcell_token = JitCellToken() jitcell_token.outermost_jitdriver_sd = jitdriver_sd @@ -359,7 +361,8 @@ enable_opts=enable_opts) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - loop_data) + loop_data, + metainterp.box_names_memo) except InvalidLoop: # Fall back on jumping directly to preamble jump_op = ResOperation(rop.JUMP, inputargs[:], descr=loop_jitcell_token) @@ -369,7 +372,8 @@ inline_short_preamble=False) try: loop_info, loop_ops = optimize_trace(metainterp_sd, jitdriver_sd, - loop_data) + loop_data, + metainterp.box_names_memo) except InvalidLoop: return None @@ -854,7 +858,7 @@ return cloned def exits_early(self): - return True + return False def attach_accum_info(self, pos, operator, arg, loc): self.rd_accum_list = \ diff --git a/rpython/jit/metainterp/jitdriver.py b/rpython/jit/metainterp/jitdriver.py --- a/rpython/jit/metainterp/jitdriver.py +++ b/rpython/jit/metainterp/jitdriver.py @@ -33,4 +33,3 @@ def _freeze_(self): return True - diff --git a/rpython/jit/metainterp/logger.py b/rpython/jit/metainterp/logger.py --- a/rpython/jit/metainterp/logger.py +++ b/rpython/jit/metainterp/logger.py @@ -138,7 +138,7 @@ return 'ConstPtr(ptr' + str(mv) + ')' return 'ConstPtr(null)' elif isinstance(arg, ConstFloat): - return str(arg.getfloatstorage()) + return str(arg.getfloat()) elif arg is None: return 'None' elif arg.is_vector(): 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 @@ -11,6 +11,7 @@ from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.debug import debug_start, debug_stop, debug_print + ALL_OPTS = [('intbounds', OptIntBounds), ('rewrite', OptRewrite), ('virtualize', OptVirtualize), @@ -52,9 +53,9 @@ """ debug_start("jit-optimize") inputargs = compile_data.start_label.getarglist() - try: - metainterp_sd.logger_noopt.log_loop(inputargs, compile_data.operations, + metainterp_sd.logger_noopt.log_loop(inputargs, + compile_data.operations, memo=memo) if memo is None: memo = {} diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -515,6 +515,7 @@ class PlainResOp(AbstractResOp): pass + class ResOpWithDescr(AbstractResOp): _descr = None @@ -1113,13 +1114,6 @@ # must be forced, however we need to execute it anyway '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations ----- - '_DEBUG_FIRST', - 'DEBUG_MERGE_POINT/*/n', # debugging only - 'ENTER_PORTAL_FRAME/2/n', # debugging only - 'LEAVE_PORTAL_FRAME/1/n', # debugging only - 'JIT_DEBUG/*/n', # debugging only - '_DEBUG_LAST', - 'INCREMENT_DEBUG_COUNTER/1/n', '_RAW_STORE_FIRST', 'SETARRAYITEM_GC/3d/n', @@ -1141,6 +1135,12 @@ 'UNICODESETITEM/3/n', 'COND_CALL_GC_WB/1d/n', # [objptr] (for the write barrier) 'COND_CALL_GC_WB_ARRAY/2d/n', # [objptr, arrayindex] (write barr. for array) + '_DEBUG_FIRST', + 'DEBUG_MERGE_POINT/*/n', # debugging only + 'ENTER_PORTAL_FRAME/2/n', # debugging only + 'LEAVE_PORTAL_FRAME/1/n', # debugging only + 'JIT_DEBUG/*/n', # debugging only + '_DEBUG_LAST', 'VIRTUAL_REF_FINISH/2/n', # removed before it's passed to the backend 'COPYSTRCONTENT/5/n', # src, dst, srcstart, dststart, length 'COPYUNICODECONTENT/5/n', @@ -1299,6 +1299,7 @@ return type(cls_name, bases, dic) setup(__name__ == '__main__') # print out the table when run directly +del _oplist _opboolinverse = { rop.INT_EQ: rop.INT_NE, diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -70,6 +70,7 @@ def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False, backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, function_threshold=4, + disable_unrolling=sys.maxint, enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, max_unroll_recursion=7, vec=1, vec_all=0, vec_cost=0, vec_length=60, vec_ratio=2, vec_guard_ratio=3, **kwds): @@ -95,6 +96,7 @@ jd.warmstate.set_param_max_retrace_guards(max_retrace_guards) jd.warmstate.set_param_enable_opts(enable_opts) jd.warmstate.set_param_max_unroll_recursion(max_unroll_recursion) + jd.warmstate.set_param_disable_unrolling(disable_unrolling) jd.warmstate.set_param_vec(vec) jd.warmstate.set_param_vec_all(vec_all) jd.warmstate.set_param_vec_cost(vec_cost) diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -381,7 +381,7 @@ if vinfo is not None: virtualizable = args[index_of_virtualizable] vinfo.clear_vable_token(virtualizable) - # + deadframe = func_execute_token(loop_token, *args) # # Record in the memmgr that we just ran this loop, From noreply at buildbot.pypy.org Wed Sep 30 15:53:12 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 30 Sep 2015 15:53:12 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: some minor reverts from defaults Message-ID: <20150930135312.ED0DE1C21A4@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79906:bec18388a99b Date: 2015-09-30 15:42 +0200 http://bitbucket.org/pypy/pypy/changeset/bec18388a99b/ Log: some minor reverts from defaults 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 @@ -144,7 +144,6 @@ descr4 = get_array_descr(c0, A4) descr5 = get_array_descr(c0, A5) descr6 = get_array_descr(c0, A6) - import pdb; pdb.set_trace() assert isinstance(descr1, ArrayDescr) assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char)) assert descr1.flag == FLAG_UNSIGNED diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -575,7 +575,7 @@ frame_depth = max(self.current_clt.frame_info.jfi_frame_depth, frame_depth_no_fixed_size + JITFRAME_FIXED_SIZE) if logger: - logger.log_bridge(inputargs, operations, "rewritten", + logger.log_bridge(inputargs, operations, "rewritten", faildescr, ops_offset=ops_offset) self.fixup_target_tokens(rawstart) self.update_frame_depth(frame_depth) @@ -1020,7 +1020,7 @@ faildescr, failargs, faillocs, frame_depth) genop_guard_list[guard_opnum](self, guard_op, guard_token, - arglocs, resloc) + arglocs, resloc) if not we_are_translated(): # must be added by the genop_guard_list[]() assert guard_token is self.pending_guard_tokens[-1] diff --git a/rpython/jit/backend/x86/test/test_rx86.py b/rpython/jit/backend/x86/test/test_rx86.py --- a/rpython/jit/backend/x86/test/test_rx86.py +++ b/rpython/jit/backend/x86/test/test_rx86.py @@ -14,9 +14,6 @@ def getvalue(self): return ''.join(self.buffer) - def clear(self): - self.buffer = [] - def force_frame_size(self, frame_size): pass From noreply at buildbot.pypy.org Wed Sep 30 15:53:14 2015 From: noreply at buildbot.pypy.org (plan_rich) Date: Wed, 30 Sep 2015 15:53:14 +0200 (CEST) Subject: [pypy-commit] pypy vecopt-merge: reverted some changes that are not necessary for the branch Message-ID: <20150930135314.F3E8E1C21A4@cobra.cs.uni-duesseldorf.de> Author: Richard Plangger Branch: vecopt-merge Changeset: r79907:fe486d25512c Date: 2015-09-30 15:53 +0200 http://bitbucket.org/pypy/pypy/changeset/fe486d25512c/ Log: reverted some changes that are not necessary for the branch diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -276,7 +276,7 @@ loop.accumulate_flat( space, self.func, obj, dtype, out, self.identity) if call__array_wrap__: - out = space.call_method(obj, '__array_wrap__', out, None) + out = space.call_method(obj, '__array_wrap__', out, space.w_None) return out axis_flags = [False] * shapelen diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -72,7 +72,7 @@ stderr = '' assert not stderr # - if discard_stdout_before_last_line or True: + if discard_stdout_before_last_line: stdout = stdout.splitlines(True)[-1] # # parse the JIT log From noreply at buildbot.pypy.org Wed Sep 30 16:25:05 2015 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 30 Sep 2015 16:25:05 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: start working on the talk Message-ID: <20150930142506.0C33B1C1193@cobra.cs.uni-duesseldorf.de> Author: fijal Branch: extradoc Changeset: r5558:e11054f8dc0a Date: 2015-09-30 16:25 +0200 http://bitbucket.org/pypy/extradoc/changeset/e11054f8dc0a/ Log: start working on the talk diff --git a/talk/pyconza2015/talk.rst b/talk/pyconza2015/talk.rst new file mode 100644 --- /dev/null +++ b/talk/pyconza2015/talk.rst @@ -0,0 +1,130 @@ + +How PyPy runs your program +================== + +About me +-------- + +* PyPy core developer for 8 years + +* running consulting business baroquesoftware.com + +This talk +--------- + +The idea is to learn: + +* how pypy runs your programs + +* how to assess the performance of your program + +* additionally, why a lot of common folklore is not true + +The basics of PyPy +------------------ + +* python interpreter, just that + +* uses magic to run code faster (most of the time) + +* different base, not written in C + +PyPy - the wider angle +---------------------- + +* download it, should come in your distribution + +* x86, x86_64, arm; windows, os x, linux + +* open source (MIT) + +PyPy - usage +------------ + +* mostly long running server programs + +* call C using cffi, a lot of libraries just work + +* use virtualenv (you should anyway) + +PyPy - magic +------------ + +* just in time compiler, replaces bytecode to assembler under your feet + +* takes a while to warm up, which defeats most short running programs + +* most of the time faster, sometimes slower + +* heavily optimizing, tons of heuristics for **typical** python programs + +PyPy - smallish example +----------------------- + +* take python code + +* run python in interpreted mode (slow) + +* run python in meta-interpreter mode (VERY SLOW) + +* compile to optimized assembler + +* repeat if necessary + +Tracing JIT +----------- + +* follow what the program is doing + +* enter special mode where all the operations are recorded + +* compile the recorded list of operations + +* add a bunch of "guards" that check that we're following the correct path + and correct optimizations + +* if guard fails, jump to interpreter + +* if guard fails enough jump to metainterpreter + +* repeat until all the paths are compiled to assembler + +Performance +----------- + +* you need a metric (response time, number of requests) + +* the less you're trying to measure, the better + +* benchmarks are a vast improvement + +* repeatability is the key + +Optimization for dummies +------------------------- + +* Obligatory citation + + - *premature optimization is the root of all evil* (D. Knuth) + +* Pareto principle, or 80-20 rule + + - 80% of the time will be spent in 20% of the program + + - 20% of 1 mln is 200 000 + +* Two golden rules: + + 1. Identify the slow spots + + 2. Optimize them + +Guidos points about optimizing python +------------------------------------- + +xxx find the link + +Why we're here? +--------------- + +yyyyy From noreply at buildbot.pypy.org Wed Sep 30 16:45:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 16:45:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for the case of a slice(5, sys.maxint) if 5 is greater than 'length' Message-ID: <20150930144536.8BE3A1C13D4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r79908:0d6164b07b67 Date: 2015-09-30 16:45 +0200 http://bitbucket.org/pypy/pypy/changeset/0d6164b07b67/ Log: Fix for the case of a slice(5, sys.maxint) if 5 is greater than 'length' diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -239,13 +239,16 @@ # hack for the JIT, for slices with no end specified: # this avoids the two comparisons that follow if jit.isconstant(stop) and stop == sys.maxint: - return start, length - if stop < start: - stop = start - if stop > length: - stop = length - if jit.isconstant(start) and start == 0: - pass # no need to do the following check here - elif start > length: - start = length + pass + else: + if stop < start: + stop = start + if stop <= length: + return start, stop + # here is the case where 'stop' is larger than the list + stop = length + if jit.isconstant(start) and start == 0: + pass # no need to do the following check here + elif start > stop: + start = stop return start, stop From noreply at buildbot.pypy.org Wed Sep 30 17:20:33 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 17:20:33 +0200 (CEST) Subject: [pypy-commit] cffi default: Maybe a fix for multiple interpreters Message-ID: <20150930152033.E5D3D1C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2293:3789df86dd71 Date: 2015-09-30 16:57 +0200 http://bitbucket.org/cffi/cffi/changeset/3789df86dd71/ Log: Maybe a fix for multiple interpreters diff --git a/c/cffi1_module.c b/c/cffi1_module.c --- a/c/cffi1_module.c +++ b/c/cffi1_module.c @@ -21,33 +21,38 @@ { PyObject *x; int i; + static int init_done = 0; if (PyType_Ready(&FFI_Type) < 0) return -1; if (PyType_Ready(&Lib_Type) < 0) return -1; - if (init_global_types_dict(FFI_Type.tp_dict) < 0) - return -1; - FFIError = PyErr_NewException("ffi.error", NULL, NULL); - if (FFIError == NULL) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CType", - (PyObject *)&CTypeDescr_Type) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", - (PyObject *)&CData_Type) < 0) - return -1; + if (!init_done) { + if (init_global_types_dict(FFI_Type.tp_dict) < 0) + return -1; - for (i = 0; all_dlopen_flags[i].name != NULL; i++) { - x = PyInt_FromLong(all_dlopen_flags[i].value); - if (x == NULL || PyDict_SetItemString(FFI_Type.tp_dict, - all_dlopen_flags[i].name, - x) < 0) + FFIError = PyErr_NewException("ffi.error", NULL, NULL); + if (FFIError == NULL) return -1; - Py_DECREF(x); + if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0) + return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "CType", + (PyObject *)&CTypeDescr_Type) < 0) + return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", + (PyObject *)&CData_Type) < 0) + return -1; + + for (i = 0; all_dlopen_flags[i].name != NULL; i++) { + x = PyInt_FromLong(all_dlopen_flags[i].value); + if (x == NULL || PyDict_SetItemString(FFI_Type.tp_dict, + all_dlopen_flags[i].name, + x) < 0) + return -1; + Py_DECREF(x); + } + init_done = 1; } x = (PyObject *)&FFI_Type; From noreply at buildbot.pypy.org Wed Sep 30 17:20:36 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 17:20:36 +0200 (CEST) Subject: [pypy-commit] cffi default: More attempts at fixes for multiple interpreters Message-ID: <20150930152036.01CF51C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2294:e312e28ae4b2 Date: 2015-09-30 17:06 +0200 http://bitbucket.org/cffi/cffi/changeset/e312e28ae4b2/ Log: More attempts at fixes for multiple interpreters diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -6289,6 +6289,7 @@ { PyObject *m, *v; int i; + static char init_done = 0; v = PySys_GetObject("version"); if (v == NULL || !PyText_Check(v) || @@ -6331,14 +6332,17 @@ if (PyType_Ready(&MiniBuffer_Type) < 0) INITERROR; - v = PyText_FromString("_cffi_backend"); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__module__", v) < 0) - INITERROR; - v = PyText_FromString(""); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__name__", v) < 0) - INITERROR; + if (!init_done) { + v = PyText_FromString("_cffi_backend"); + if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, + "__module__", v) < 0) + INITERROR; + v = PyText_FromString(""); + if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, + "__name__", v) < 0) + INITERROR; + init_done = 1; + } /* this is for backward compatibility only */ v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); @@ -6377,6 +6381,8 @@ } init_errno(); + if (PyErr_Occurred()) + INITERROR; if (init_ffi_lib(m) < 0) INITERROR; diff --git a/c/cffi1_module.c b/c/cffi1_module.c --- a/c/cffi1_module.c +++ b/c/cffi1_module.c @@ -21,7 +21,7 @@ { PyObject *x; int i; - static int init_done = 0; + static char init_done = 0; if (PyType_Ready(&FFI_Type) < 0) return -1; diff --git a/c/file_emulator.h b/c/file_emulator.h --- a/c/file_emulator.h +++ b/c/file_emulator.h @@ -5,12 +5,14 @@ static int init_file_emulator(void) { - PyObject *io = PyImport_ImportModule("_io"); - if (io == NULL) - return -1; - PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); - if (PyIOBase_TypeObj == NULL) - return -1; + if (PyIOBase_TypeObj == NULL) { + PyObject *io = PyImport_ImportModule("_io"); + if (io == NULL) + return -1; + PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); + if (PyIOBase_TypeObj == NULL) + return -1; + } return 0; } diff --git a/c/misc_win32.h b/c/misc_win32.h --- a/c/misc_win32.h +++ b/c/misc_win32.h @@ -8,13 +8,15 @@ int saved_lasterror; }; -static DWORD cffi_tls_index; +static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES; static void init_errno(void) { - cffi_tls_index = TlsAlloc(); - if (cffi_tls_index == TLS_OUT_OF_INDEXES) - PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); + if (cffi_tls_index == TLS_OUT_OF_INDEXES) { + cffi_tls_index = TlsAlloc(); + if (cffi_tls_index == TLS_OUT_OF_INDEXES) + PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); + } } static struct cffi_errno_s *_geterrno_object(void) From noreply at buildbot.pypy.org Wed Sep 30 17:20:38 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 17:20:38 +0200 (CEST) Subject: [pypy-commit] cffi default: One more place Message-ID: <20150930152038.044A41C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2295:d775ed0dc13c Date: 2015-09-30 17:07 +0200 http://bitbucket.org/cffi/cffi/changeset/d775ed0dc13c/ Log: One more place diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -6309,9 +6309,11 @@ if (m == NULL) INITERROR; - unique_cache = PyDict_New(); - if (unique_cache == NULL) - INITERROR; + if (unique_cache == NULL) { + unique_cache = PyDict_New(); + if (unique_cache == NULL) + INITERROR; + } if (PyType_Ready(&dl_type) < 0) INITERROR; From noreply at buildbot.pypy.org Wed Sep 30 17:20:40 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 17:20:40 +0200 (CEST) Subject: [pypy-commit] cffi default: Make the type objects mortal Message-ID: <20150930152040.0F1D41C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2296:9ad33a44f60f Date: 2015-09-30 17:17 +0200 http://bitbucket.org/cffi/cffi/changeset/9ad33a44f60f/ Log: Make the type objects mortal diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -155,6 +155,9 @@ PyObject *ct_weakreflist; /* weakref support */ + PyObject *ct_unique_key; /* key in unique_cache (a string, but not + human-readable) */ + Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; or alignment of primitive and struct types; @@ -286,6 +289,7 @@ typedef PyObject *const cffi_allocator_t[3]; static cffi_allocator_t default_allocator = { NULL, NULL, NULL }; static PyObject *FFIError; +static PyObject *unique_cache; /************************************************************/ @@ -301,6 +305,7 @@ ct->ct_itemdescr = NULL; ct->ct_stuff = NULL; ct->ct_weakreflist = NULL; + ct->ct_unique_key = NULL; PyObject_GC_Track(ct); return ct; } @@ -343,6 +348,15 @@ PyObject_GC_UnTrack(ct); if (ct->ct_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) ct); + + if (ct->ct_unique_key != NULL) { + /* revive dead object temporarily for DelItem */ + Py_REFCNT(ct) = 43; + PyDict_DelItem(unique_cache, ct->ct_unique_key); + assert(Py_REFCNT(ct) == 42); + Py_REFCNT(ct) = 0; + Py_DECREF(ct->ct_unique_key); + } Py_XDECREF(ct->ct_itemdescr); Py_XDECREF(ct->ct_stuff); if (ct->ct_flags & CT_FUNCTIONPTR) @@ -3612,8 +3626,6 @@ /************************************************************/ -static PyObject *unique_cache; - static PyObject *get_unique_type(CTypeDescrObject *x, const void *unique_key[], long keylength) { @@ -3633,7 +3645,6 @@ */ PyObject *key, *y; const void **pkey; - int err; key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); if (key == NULL) @@ -3649,11 +3660,14 @@ Py_DECREF(x); return y; } - err = PyDict_SetItem(unique_cache, key, (PyObject *)x); - Py_DECREF(key); - if (err < 0) + if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { + Py_DECREF(key); goto error; - + } + + assert(x->ct_unique_key == NULL); + x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ + Py_DECREF(x); /* the 'value' in unique_cache doesn't count as 1 */ return (PyObject *)x; error: diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py --- a/testing/cffi1/test_ffi_obj.py +++ b/testing/cffi1/test_ffi_obj.py @@ -29,6 +29,32 @@ assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]") assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()") +def test_ffi_type_not_immortal(): + import weakref, gc + ffi = _cffi1_backend.FFI() + t1 = ffi.typeof("int **") + t2 = ffi.typeof("int *") + w1 = weakref.ref(t1) + w2 = weakref.ref(t2) + del t1, ffi + gc.collect() + assert w1() is None + assert w2() is t2 + ffi = _cffi1_backend.FFI() + assert ffi.typeof(ffi.new("int **")[0]) is t2 + # + ffi = _cffi1_backend.FFI() + t1 = ffi.typeof("int ***") + t2 = ffi.typeof("int **") + w1 = weakref.ref(t1) + w2 = weakref.ref(t2) + del t2, ffi + gc.collect() + assert w1() is t1 + assert w2() is not None # kept alive by t1 + ffi = _cffi1_backend.FFI() + assert ffi.typeof("int * *") is t1.item + def test_ffi_cache_type_globally(): ffi1 = _cffi1_backend.FFI() ffi2 = _cffi1_backend.FFI() From noreply at buildbot.pypy.org Wed Sep 30 17:20:41 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 17:20:41 +0200 (CEST) Subject: [pypy-commit] cffi default: test fix Message-ID: <20150930152041.F25C21C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2297:059aca3cb3dc Date: 2015-09-30 17:19 +0200 http://bitbucket.org/cffi/cffi/changeset/059aca3cb3dc/ Log: test fix diff --git a/testing/cffi0/test_model.py b/testing/cffi0/test_model.py --- a/testing/cffi0/test_model.py +++ b/testing/cffi0/test_model.py @@ -59,7 +59,7 @@ def test_qual_pointer_type(): ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT) - assert ptr_type.get_c_name("") == "long long restrict *" + assert ptr_type.get_c_name("") == "long long __restrict *" assert const_voidp_type.get_c_name("") == "void const *" def test_unknown_pointer_type(): From noreply at buildbot.pypy.org Wed Sep 30 18:36:46 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 18:36:46 +0200 (CEST) Subject: [pypy-commit] pypy py3.3: hg merge d12dfd19fd86 Message-ID: <20150930163646.854271C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: py3.3 Changeset: r79909:4fa19970ddeb Date: 2015-09-30 17:39 +0100 http://bitbucket.org/pypy/pypy/changeset/4fa19970ddeb/ Log: hg merge d12dfd19fd86 This includes a few more commits from "default" which fix two problems: - an issue with pinned objects - linux asmgcc was broken diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -166,7 +166,7 @@ # The marking phase. We walk the list 'objects_to_trace' of all gray objects # and mark all of the things they point to gray. This step lasts until there -# are no more gray objects. +# are no more gray objects. ('objects_to_trace' never contains pinned objs.) STATE_MARKING = 1 # here we kill all the unvisited objects @@ -1146,6 +1146,9 @@ "raw_malloc_might_sweep must be empty outside SWEEPING") if self.gc_state == STATE_MARKING: + self.objects_to_trace.foreach(self._check_not_in_nursery, None) + self.more_objects_to_trace.foreach(self._check_not_in_nursery, + None) self._debug_objects_to_trace_dict1 = \ self.objects_to_trace.stack2dict() self._debug_objects_to_trace_dict2 = \ @@ -1156,6 +1159,10 @@ else: MovingGCBase.debug_check_consistency(self) + def _check_not_in_nursery(self, obj, ignore): + ll_assert(not self.is_in_nursery(obj), + "'objects_to_trace' contains a nursery object") + def debug_check_object(self, obj): # We are after a minor collection, and possibly after a major # collection step. No object should be in the nursery (except @@ -1789,6 +1796,8 @@ # If we're incrementally marking right now, sorry, we also # need to add the object to 'more_objects_to_trace' and have # it fully traced once at the end of the current marking phase. + ll_assert(not self.is_in_nursery(obj), + "expected nursery obj in collect_cardrefs_to_nursery") if self.gc_state == STATE_MARKING: self.header(obj).tid &= ~GCFLAG_VISITED self.more_objects_to_trace.append(obj) @@ -1845,8 +1854,11 @@ # need to record the not-visited-yet (white) old objects. So # as a conservative approximation, we need to add the object to # the list if and only if it doesn't have GCFLAG_VISITED yet. + # + # Additionally, ignore pinned objects. + # obj = root.address[0] - if not self.header(obj).tid & GCFLAG_VISITED: + if (self.header(obj).tid & (GCFLAG_VISITED | GCFLAG_PINNED)) == 0: self.more_objects_to_trace.append(obj) def _trace_drag_out(self, root, parent): @@ -1899,7 +1911,7 @@ # self.old_objects_pointing_to_pinned.append(parent) self.updated_old_objects_pointing_to_pinned = True - self.header(parent).tid |= GCFLAG_PINNED + self.header(parent).tid |= GCFLAG_PINNED_OBJECT_PARENT_KNOWN # if hdr.tid & GCFLAG_VISITED: return @@ -2033,6 +2045,7 @@ new.delete() def _add_to_more_objects_to_trace(self, obj, ignored): + ll_assert(not self.is_in_nursery(obj), "unexpected nursery obj here") self.header(obj).tid &= ~GCFLAG_VISITED self.more_objects_to_trace.append(obj) @@ -2287,8 +2300,7 @@ def collect_roots(self): # Collect all roots. Starts from all the objects # from 'prebuilt_root_objects'. - self.prebuilt_root_objects.foreach(self._collect_obj, - self.objects_to_trace) + self.prebuilt_root_objects.foreach(self._collect_obj, None) # # Add the roots from the other sources. self.root_walker.walk_roots( @@ -2298,43 +2310,48 @@ # # If we are in an inner collection caused by a call to a finalizer, # the 'run_finalizers' objects also need to be kept alive. - self.run_finalizers.foreach(self._collect_obj, - self.objects_to_trace) + self.run_finalizers.foreach(self._collect_obj, None) def enumerate_all_roots(self, callback, arg): self.prebuilt_root_objects.foreach(callback, arg) MovingGCBase.enumerate_all_roots(self, callback, arg) enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)' - @staticmethod - def _collect_obj(obj, objects_to_trace): - objects_to_trace.append(obj) + def _collect_obj(self, obj, ignored): + # Ignore pinned objects, which are the ones still in the nursery here. + # Cache effects: don't read any flag out of 'obj' at this point. + # But only checking if it is in the nursery or not is fine. + llop.debug_nonnull_pointer(lltype.Void, obj) + if not self.is_in_nursery(obj): + self.objects_to_trace.append(obj) + else: + # A pinned object can be found here. Such an object is handled + # by minor collections and shouldn't be specially handled by + # major collections. Therefore we only add non-pinned objects + # to the 'objects_to_trace' list. + ll_assert(self._is_pinned(obj), + "non-pinned nursery obj in _collect_obj") + _collect_obj._always_inline_ = True def _collect_ref_stk(self, root): - obj = root.address[0] - llop.debug_nonnull_pointer(lltype.Void, obj) - if not self._is_pinned(obj): - # XXX: check if this is the right way (groggi). - # A pinned object can be on the stack. Such an object is handled - # by minor collections and shouldn't be specially handled by - # major collections. Therefore we only add not pinned objects to the - # list below. - self.objects_to_trace.append(obj) + self._collect_obj(root.address[0], None) def _collect_ref_rec(self, root, ignored): - self.objects_to_trace.append(root.address[0]) + self._collect_obj(root.address[0], None) def visit_all_objects(self): while self.objects_to_trace.non_empty(): self.visit_all_objects_step(sys.maxint) + TEST_VISIT_SINGLE_STEP = False # for tests + def visit_all_objects_step(self, size_to_track): # Objects can be added to pending by visit pending = self.objects_to_trace while pending.non_empty(): obj = pending.pop() size_to_track -= self.visit(obj) - if size_to_track < 0: + if size_to_track < 0 or self.TEST_VISIT_SINGLE_STEP: return 0 return size_to_track @@ -2349,10 +2366,17 @@ # flag set, then the object should be in 'prebuilt_root_objects', # and the GCFLAG_VISITED will be reset at the end of the # collection. - # Objects with GCFLAG_PINNED can't have gcptrs (see pin()), they can be - # ignored. + # We shouldn't see an object with GCFLAG_PINNED here (the pinned + # objects are never added to 'objects_to_trace'). The same-valued + # flag GCFLAG_PINNED_OBJECT_PARENT_KNOWN is used during minor + # collections and shouldn't be set here either. + # hdr = self.header(obj) - if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS | GCFLAG_PINNED): + ll_assert((hdr.tid & GCFLAG_PINNED) == 0, + "pinned object in 'objects_to_trace'") + ll_assert(not self.is_in_nursery(obj), + "nursery object in 'objects_to_trace'") + if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS): return 0 # # It's the first time. We set the flag VISITED. The trick is @@ -2582,6 +2606,7 @@ # recursively convert objects from state 1 to state 2. # The call to visit_all_objects() will add the GCFLAG_VISITED # recursively. + ll_assert(not self.is_in_nursery(obj), "pinned finalizer object??") self.objects_to_trace.append(obj) self.visit_all_objects() diff --git a/rpython/memory/gc/test/test_object_pinning.py b/rpython/memory/gc/test/test_object_pinning.py --- a/rpython/memory/gc/test/test_object_pinning.py +++ b/rpython/memory/gc/test/test_object_pinning.py @@ -88,7 +88,7 @@ class TestIncminimark(PinningGCTest): from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass - from rpython.memory.gc.incminimark import STATE_SCANNING + from rpython.memory.gc.incminimark import STATE_SCANNING, STATE_MARKING def test_try_pin_gcref_containing_type(self): # scenario: incminimark's object pinning can't pin objects that may @@ -917,3 +917,65 @@ py.test.raises(Exception, self.malloc, T) test_full_pinned_nursery_pin_fail.max_number_of_pinned_objects = 50 + + def test_pin_bug1(self): + # + # * the nursery contains a pinned object 'ptr1' + # + # * outside the nursery is another object 'ptr2' pointing to 'ptr1' + # + # * during one incremental tracing step, we see 'ptr2' but don't + # trace 'ptr1' right now: it is left behind on the trace-me-later + # list + # + # * then we run the program, unpin 'ptr1', and remove it from 'ptr2' + # + # * at the next minor collection, we free 'ptr1' because we don't + # find anything pointing to it (it is removed from 'ptr2'), + # but 'ptr1' is still in the trace-me-later list + # + # * the trace-me-later list is deep enough that 'ptr1' is not + # seen right now! it is only seen at some later minor collection + # + # * at that later point, crash, because 'ptr1' in the nursery was + # overwritten + # + ptr2 = self.malloc(S) + ptr2.someInt = 102 + self.stackroots.append(ptr2) + + self.gc.collect() + ptr2 = self.stackroots[-1] # now outside the nursery + adr2 = llmemory.cast_ptr_to_adr(ptr2) + + ptr1 = self.malloc(T) + adr1 = llmemory.cast_ptr_to_adr(ptr1) + ptr1.someInt = 101 + self.write(ptr2, 'data', ptr1) + res = self.gc.pin(adr1) + assert res + + self.gc.minor_collection() + assert self.gc.gc_state == self.STATE_SCANNING + self.gc.major_collection_step() + assert self.gc.objects_to_trace.tolist() == [adr2] + assert self.gc.more_objects_to_trace.tolist() == [] + + self.gc.TEST_VISIT_SINGLE_STEP = True + + self.gc.minor_collection() + assert self.gc.gc_state == self.STATE_MARKING + self.gc.major_collection_step() + assert self.gc.objects_to_trace.tolist() == [] + assert self.gc.more_objects_to_trace.tolist() == [adr2] + + self.write(ptr2, 'data', lltype.nullptr(T)) + self.gc.unpin(adr1) + + assert ptr1.someInt == 101 + self.gc.minor_collection() # should free 'ptr1' + py.test.raises(RuntimeError, "ptr1.someInt") + assert self.gc.gc_state == self.STATE_MARKING + self.gc.major_collection_step() # should not crash reading 'ptr1'! + + del self.gc.TEST_VISIT_SINGLE_STEP diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py --- a/rpython/rlib/rvmprof/cintf.py +++ b/rpython/rlib/rvmprof/cintf.py @@ -90,8 +90,14 @@ cont_name = '_' + cont_name tramp_name = '_' + tramp_name PLT = "" + size_decl = "" + type_decl = "" else: PLT = "@PLT" + type_decl = "\t.type\t%s, @function" % (tramp_name,) + size_decl = "\t.size\t%s, .-%s" % ( + tramp_name, tramp_name) + assert detect_cpu.autodetect().startswith(detect_cpu.MODEL_X86_64), ( "rvmprof only supports x86-64 CPUs for now") @@ -114,9 +120,12 @@ target = udir.join('module_cache') target.ensure(dir=1) target = target.join('trampoline_%s_%s.vmprof.s' % (name, token)) + # NOTE! the tabs in this file are absolutely essential, things + # that don't start with \t are silently ignored (: WAT!?) target.write("""\ \t.text \t.globl\t%(tramp_name)s +%(type_decl)s %(tramp_name)s: \t.cfi_startproc \tpushq\t%(reg)s @@ -126,6 +135,7 @@ \t.cfi_def_cfa_offset 8 \tret \t.cfi_endproc +%(size_decl)s """ % locals()) def tok2cname(tok): From noreply at buildbot.pypy.org Wed Sep 30 18:40:56 2015 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 30 Sep 2015 18:40:56 +0200 (CEST) Subject: [pypy-commit] pypy py3k: hg merge d12dfd19fd86 Message-ID: <20150930164057.011DE1C1311@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: py3k Changeset: r79910:bed78253f4c5 Date: 2015-09-30 18:41 +0200 http://bitbucket.org/pypy/pypy/changeset/bed78253f4c5/ Log: hg merge d12dfd19fd86 same as 4fa19970ddeb for the py3k branch diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -166,7 +166,7 @@ # The marking phase. We walk the list 'objects_to_trace' of all gray objects # and mark all of the things they point to gray. This step lasts until there -# are no more gray objects. +# are no more gray objects. ('objects_to_trace' never contains pinned objs.) STATE_MARKING = 1 # here we kill all the unvisited objects @@ -1146,6 +1146,9 @@ "raw_malloc_might_sweep must be empty outside SWEEPING") if self.gc_state == STATE_MARKING: + self.objects_to_trace.foreach(self._check_not_in_nursery, None) + self.more_objects_to_trace.foreach(self._check_not_in_nursery, + None) self._debug_objects_to_trace_dict1 = \ self.objects_to_trace.stack2dict() self._debug_objects_to_trace_dict2 = \ @@ -1156,6 +1159,10 @@ else: MovingGCBase.debug_check_consistency(self) + def _check_not_in_nursery(self, obj, ignore): + ll_assert(not self.is_in_nursery(obj), + "'objects_to_trace' contains a nursery object") + def debug_check_object(self, obj): # We are after a minor collection, and possibly after a major # collection step. No object should be in the nursery (except @@ -1789,6 +1796,8 @@ # If we're incrementally marking right now, sorry, we also # need to add the object to 'more_objects_to_trace' and have # it fully traced once at the end of the current marking phase. + ll_assert(not self.is_in_nursery(obj), + "expected nursery obj in collect_cardrefs_to_nursery") if self.gc_state == STATE_MARKING: self.header(obj).tid &= ~GCFLAG_VISITED self.more_objects_to_trace.append(obj) @@ -1845,8 +1854,11 @@ # need to record the not-visited-yet (white) old objects. So # as a conservative approximation, we need to add the object to # the list if and only if it doesn't have GCFLAG_VISITED yet. + # + # Additionally, ignore pinned objects. + # obj = root.address[0] - if not self.header(obj).tid & GCFLAG_VISITED: + if (self.header(obj).tid & (GCFLAG_VISITED | GCFLAG_PINNED)) == 0: self.more_objects_to_trace.append(obj) def _trace_drag_out(self, root, parent): @@ -1899,7 +1911,7 @@ # self.old_objects_pointing_to_pinned.append(parent) self.updated_old_objects_pointing_to_pinned = True - self.header(parent).tid |= GCFLAG_PINNED + self.header(parent).tid |= GCFLAG_PINNED_OBJECT_PARENT_KNOWN # if hdr.tid & GCFLAG_VISITED: return @@ -2033,6 +2045,7 @@ new.delete() def _add_to_more_objects_to_trace(self, obj, ignored): + ll_assert(not self.is_in_nursery(obj), "unexpected nursery obj here") self.header(obj).tid &= ~GCFLAG_VISITED self.more_objects_to_trace.append(obj) @@ -2287,8 +2300,7 @@ def collect_roots(self): # Collect all roots. Starts from all the objects # from 'prebuilt_root_objects'. - self.prebuilt_root_objects.foreach(self._collect_obj, - self.objects_to_trace) + self.prebuilt_root_objects.foreach(self._collect_obj, None) # # Add the roots from the other sources. self.root_walker.walk_roots( @@ -2298,43 +2310,48 @@ # # If we are in an inner collection caused by a call to a finalizer, # the 'run_finalizers' objects also need to be kept alive. - self.run_finalizers.foreach(self._collect_obj, - self.objects_to_trace) + self.run_finalizers.foreach(self._collect_obj, None) def enumerate_all_roots(self, callback, arg): self.prebuilt_root_objects.foreach(callback, arg) MovingGCBase.enumerate_all_roots(self, callback, arg) enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)' - @staticmethod - def _collect_obj(obj, objects_to_trace): - objects_to_trace.append(obj) + def _collect_obj(self, obj, ignored): + # Ignore pinned objects, which are the ones still in the nursery here. + # Cache effects: don't read any flag out of 'obj' at this point. + # But only checking if it is in the nursery or not is fine. + llop.debug_nonnull_pointer(lltype.Void, obj) + if not self.is_in_nursery(obj): + self.objects_to_trace.append(obj) + else: + # A pinned object can be found here. Such an object is handled + # by minor collections and shouldn't be specially handled by + # major collections. Therefore we only add non-pinned objects + # to the 'objects_to_trace' list. + ll_assert(self._is_pinned(obj), + "non-pinned nursery obj in _collect_obj") + _collect_obj._always_inline_ = True def _collect_ref_stk(self, root): - obj = root.address[0] - llop.debug_nonnull_pointer(lltype.Void, obj) - if not self._is_pinned(obj): - # XXX: check if this is the right way (groggi). - # A pinned object can be on the stack. Such an object is handled - # by minor collections and shouldn't be specially handled by - # major collections. Therefore we only add not pinned objects to the - # list below. - self.objects_to_trace.append(obj) + self._collect_obj(root.address[0], None) def _collect_ref_rec(self, root, ignored): - self.objects_to_trace.append(root.address[0]) + self._collect_obj(root.address[0], None) def visit_all_objects(self): while self.objects_to_trace.non_empty(): self.visit_all_objects_step(sys.maxint) + TEST_VISIT_SINGLE_STEP = False # for tests + def visit_all_objects_step(self, size_to_track): # Objects can be added to pending by visit pending = self.objects_to_trace while pending.non_empty(): obj = pending.pop() size_to_track -= self.visit(obj) - if size_to_track < 0: + if size_to_track < 0 or self.TEST_VISIT_SINGLE_STEP: return 0 return size_to_track @@ -2349,10 +2366,17 @@ # flag set, then the object should be in 'prebuilt_root_objects', # and the GCFLAG_VISITED will be reset at the end of the # collection. - # Objects with GCFLAG_PINNED can't have gcptrs (see pin()), they can be - # ignored. + # We shouldn't see an object with GCFLAG_PINNED here (the pinned + # objects are never added to 'objects_to_trace'). The same-valued + # flag GCFLAG_PINNED_OBJECT_PARENT_KNOWN is used during minor + # collections and shouldn't be set here either. + # hdr = self.header(obj) - if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS | GCFLAG_PINNED): + ll_assert((hdr.tid & GCFLAG_PINNED) == 0, + "pinned object in 'objects_to_trace'") + ll_assert(not self.is_in_nursery(obj), + "nursery object in 'objects_to_trace'") + if hdr.tid & (GCFLAG_VISITED | GCFLAG_NO_HEAP_PTRS): return 0 # # It's the first time. We set the flag VISITED. The trick is @@ -2582,6 +2606,7 @@ # recursively convert objects from state 1 to state 2. # The call to visit_all_objects() will add the GCFLAG_VISITED # recursively. + ll_assert(not self.is_in_nursery(obj), "pinned finalizer object??") self.objects_to_trace.append(obj) self.visit_all_objects() diff --git a/rpython/memory/gc/test/test_object_pinning.py b/rpython/memory/gc/test/test_object_pinning.py --- a/rpython/memory/gc/test/test_object_pinning.py +++ b/rpython/memory/gc/test/test_object_pinning.py @@ -88,7 +88,7 @@ class TestIncminimark(PinningGCTest): from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass - from rpython.memory.gc.incminimark import STATE_SCANNING + from rpython.memory.gc.incminimark import STATE_SCANNING, STATE_MARKING def test_try_pin_gcref_containing_type(self): # scenario: incminimark's object pinning can't pin objects that may @@ -917,3 +917,65 @@ py.test.raises(Exception, self.malloc, T) test_full_pinned_nursery_pin_fail.max_number_of_pinned_objects = 50 + + def test_pin_bug1(self): + # + # * the nursery contains a pinned object 'ptr1' + # + # * outside the nursery is another object 'ptr2' pointing to 'ptr1' + # + # * during one incremental tracing step, we see 'ptr2' but don't + # trace 'ptr1' right now: it is left behind on the trace-me-later + # list + # + # * then we run the program, unpin 'ptr1', and remove it from 'ptr2' + # + # * at the next minor collection, we free 'ptr1' because we don't + # find anything pointing to it (it is removed from 'ptr2'), + # but 'ptr1' is still in the trace-me-later list + # + # * the trace-me-later list is deep enough that 'ptr1' is not + # seen right now! it is only seen at some later minor collection + # + # * at that later point, crash, because 'ptr1' in the nursery was + # overwritten + # + ptr2 = self.malloc(S) + ptr2.someInt = 102 + self.stackroots.append(ptr2) + + self.gc.collect() + ptr2 = self.stackroots[-1] # now outside the nursery + adr2 = llmemory.cast_ptr_to_adr(ptr2) + + ptr1 = self.malloc(T) + adr1 = llmemory.cast_ptr_to_adr(ptr1) + ptr1.someInt = 101 + self.write(ptr2, 'data', ptr1) + res = self.gc.pin(adr1) + assert res + + self.gc.minor_collection() + assert self.gc.gc_state == self.STATE_SCANNING + self.gc.major_collection_step() + assert self.gc.objects_to_trace.tolist() == [adr2] + assert self.gc.more_objects_to_trace.tolist() == [] + + self.gc.TEST_VISIT_SINGLE_STEP = True + + self.gc.minor_collection() + assert self.gc.gc_state == self.STATE_MARKING + self.gc.major_collection_step() + assert self.gc.objects_to_trace.tolist() == [] + assert self.gc.more_objects_to_trace.tolist() == [adr2] + + self.write(ptr2, 'data', lltype.nullptr(T)) + self.gc.unpin(adr1) + + assert ptr1.someInt == 101 + self.gc.minor_collection() # should free 'ptr1' + py.test.raises(RuntimeError, "ptr1.someInt") + assert self.gc.gc_state == self.STATE_MARKING + self.gc.major_collection_step() # should not crash reading 'ptr1'! + + del self.gc.TEST_VISIT_SINGLE_STEP diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py --- a/rpython/rlib/rvmprof/cintf.py +++ b/rpython/rlib/rvmprof/cintf.py @@ -90,8 +90,14 @@ cont_name = '_' + cont_name tramp_name = '_' + tramp_name PLT = "" + size_decl = "" + type_decl = "" else: PLT = "@PLT" + type_decl = "\t.type\t%s, @function" % (tramp_name,) + size_decl = "\t.size\t%s, .-%s" % ( + tramp_name, tramp_name) + assert detect_cpu.autodetect().startswith(detect_cpu.MODEL_X86_64), ( "rvmprof only supports x86-64 CPUs for now") @@ -114,9 +120,12 @@ target = udir.join('module_cache') target.ensure(dir=1) target = target.join('trampoline_%s_%s.vmprof.s' % (name, token)) + # NOTE! the tabs in this file are absolutely essential, things + # that don't start with \t are silently ignored (: WAT!?) target.write("""\ \t.text \t.globl\t%(tramp_name)s +%(type_decl)s %(tramp_name)s: \t.cfi_startproc \tpushq\t%(reg)s @@ -126,6 +135,7 @@ \t.cfi_def_cfa_offset 8 \tret \t.cfi_endproc +%(size_decl)s """ % locals()) def tok2cname(tok): From noreply at buildbot.pypy.org Wed Sep 30 22:18:08 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 22:18:08 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: implement order, pass many tests Message-ID: <20150930201808.7F4B31C1F1E@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79911:a14943e46cef Date: 2015-09-30 23:17 +0300 http://bitbucket.org/pypy/pypy/changeset/a14943e46cef/ Log: implement order, pass many tests diff --git a/pypy/module/micronumpy/arrayops.py b/pypy/module/micronumpy/arrayops.py --- a/pypy/module/micronumpy/arrayops.py +++ b/pypy/module/micronumpy/arrayops.py @@ -108,7 +108,8 @@ w_axis = space.wrap(0) if space.is_none(w_axis): args_w = [w_arg.reshape(space, - space.newlist([w_arg.descr_get_size(space)])) + space.newlist([w_arg.descr_get_size(space)]), + w_arg.get_order()) for w_arg in args_w] w_axis = space.wrap(0) dtype = args_w[0].get_dtype() diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -92,17 +92,18 @@ def get_storage_size(self): return self.size - def reshape(self, orig_array, new_shape): + def reshape(self, orig_array, new_shape, order=NPY.ANYORDER): # Since we got to here, prod(new_shape) == self.size + order = support.get_order_as_CF(self.order, order) new_strides = None if self.size == 0: - new_strides, _ = calc_strides(new_shape, self.dtype, self.order) + new_strides, _ = calc_strides(new_shape, self.dtype, order) else: if len(self.get_shape()) == 0: new_strides = [self.dtype.elsize] * len(new_shape) else: new_strides = calc_new_strides(new_shape, self.get_shape(), - self.get_strides(), self.order) + self.get_strides(), order) if new_strides is None or len(new_strides) != len(new_shape): return None if new_strides is not None: @@ -306,10 +307,11 @@ return SliceArray(self.start, strides, backstrides, shape, self, orig_array) - def copy(self, space): + def copy(self, space, order=NPY.ANYORDER): + order = support.get_order_as_CF(self.order, order) strides, backstrides = calc_strides(self.get_shape(), self.dtype, - self.order) - impl = ConcreteArray(self.get_shape(), self.dtype, self.order, strides, + order) + impl = ConcreteArray(self.get_shape(), self.dtype, order, strides, backstrides) return loop.setslice(space, self.get_shape(), impl, self) diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -201,6 +201,7 @@ def _zeros_or_empty(space, w_shape, w_dtype, w_order, zero): + order = order_converter(space, w_order, NPY.CORDER) dtype = space.interp_w(descriptor.W_Dtype, space.call_function(space.gettypefor(descriptor.W_Dtype), w_dtype)) if dtype.is_str_or_unicode() and dtype.elsize < 1: @@ -214,7 +215,7 @@ support.product_check(shape) except OverflowError: raise oefmt(space.w_ValueError, "array is too big.") - return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) + return W_NDimArray.from_shape(space, shape, dtype, order, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): return _zeros_or_empty(space, w_shape, w_dtype, w_order, zero=False) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -680,8 +680,7 @@ def tostring(space, arr): builder = StringBuilder() iter, state = arr.create_iter() - w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), - order=NPY.CORDER) + w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype()) itemsize = arr.get_dtype().elsize with w_res_str.implementation as storage: res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char), diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -99,12 +99,13 @@ def descr_tostring(self, space, w_order=None): try: order = order_converter(space, w_order, NPY.CORDER) - except OperationError as e: - raise oefmt(space.w_TypeError, "order not understood") - if order == NPY.FORTRANORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) - return space.wrap(loop.tostring(space, self)) + except: + raise oefmt(space.w_TypeError, "order not understood") + order = support.get_order_as_CF(self.get_order(), order) + arr = self + if order != arr.get_order(): + arr = W_NDimArray(self.implementation.transpose(self, None)) + return space.wrap(loop.tostring(space, arr)) def getitem_filter(self, space, arr): if arr.ndims() > 1 and arr.get_shape() != self.get_shape(): @@ -374,10 +375,7 @@ order = space.int_w(w_order) else: order = order_converter(space, w_order, NPY.KEEPORDER) - if order == NPY.FORTRANORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) - copy = self.implementation.copy(space) + copy = self.implementation.copy(space, order) w_subtype = space.type(self) return wrap_impl(space, w_subtype, self, copy) @@ -400,15 +398,15 @@ 'array does not have imaginary part to set') self.implementation.set_imag(space, self, w_value) - def reshape(self, space, w_shape): + def reshape(self, space, w_shape, order): new_shape = get_shape_from_iterable(space, self.get_size(), w_shape) - new_impl = self.implementation.reshape(self, new_shape) + new_impl = self.implementation.reshape(self, new_shape, order) if new_impl is not None: return wrap_impl(space, space.type(self), self, new_impl) # Create copy with contiguous data - arr = self.descr_copy(space) + arr = self.descr_copy(space, space.wrap(order)) if arr.get_size() > 0: - new_implementation = arr.implementation.reshape(self, new_shape) + new_implementation = arr.implementation.reshape(self, new_shape, order) if new_implementation is None: raise oefmt(space.w_ValueError, 'could not reshape array of size %d to shape %s', @@ -442,16 +440,13 @@ if order == NPY.KEEPORDER: raise OperationError(space.w_ValueError, space.wrap( "order 'K' is not permitted for reshaping")) - if order != NPY.CORDER and order != NPY.ANYORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) if len(args_w) == 1: if space.is_none(args_w[0]): return self.descr_view(space) w_shape = args_w[0] else: w_shape = space.newtuple(args_w) - return self.reshape(space, w_shape) + return self.reshape(space, w_shape, order) def descr_get_transpose(self, space, axes=None): return W_NDimArray(self.implementation.transpose(self, axes)) @@ -522,20 +517,8 @@ return space.newlist(l_w) def descr_ravel(self, space, w_order=None): - if space.is_none(w_order): - order = 'C' - else: - order = space.str_w(w_order) - if order == 'K' and is_c_contiguous(self.implementation): - for s in self.implementation.get_strides(): - if s < 0: - break - else: - order = 'C' - if order != 'C': - raise OperationError(space.w_NotImplementedError, space.wrap( - "order != 'C' only partially implemented")) - return self.reshape(space, space.wrap(-1)) + order = order_converter(space, w_order, self.get_order()) + return self.reshape(space, space.wrap(-1), order) @unwrap_spec(w_axis=WrappedDefault(None), w_out=WrappedDefault(None), @@ -549,14 +532,15 @@ space.wrap("axis unsupported for compress")) arr = self else: - arr = self.reshape(space, space.wrap(-1)) + arr = self.reshape(space, space.wrap(-1), self.get_order()) index = convert_to_array(space, w_obj) return arr.getitem_filter(space, index) def descr_flatten(self, space, w_order=None): + order = order_converter(space, w_order, self.get_order()) if self.is_scalar(): # scalars have no storage - return self.reshape(space, space.wrap(1)) + return self.reshape(space, space.wrap(1), order) w_res = self.descr_ravel(space, w_order) if w_res.implementation.storage == self.implementation.storage: return w_res.descr_copy(space) @@ -1202,7 +1186,7 @@ out = out_converter(space, w_out) if space.is_none(w_axis): w_axis = space.wrap(0) - arr = self.reshape(space, space.wrap(-1)) + arr = self.reshape(space, space.wrap(-1), self.get_order()) else: arr = self ufunc = getattr(ufuncs.get(space), ufunc_name) diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -144,14 +144,13 @@ 'Iterator flag EXTERNAL_LOOP cannot be used if an index or ' 'multi-index is being tracked') - -def is_backward(imp, order): - if order == NPY.KEEPORDER or (order == NPY.CORDER and imp.order == NPY.CORDER): +def is_backward(imp_order, order): + if imp_order == order: return False - elif order == NPY.FORTRANORDER and imp.order == NPY.CORDER: + if order == NPY.KEEPORDER: + return False + else: return True - else: - raise NotImplementedError('not implemented yet') class OperandIter(ArrayIter): @@ -514,7 +513,7 @@ dtype = self.dtypes[i] shape = self.shape imp = arr.implementation - backward = is_backward(imp, self.order) + backward = is_backward(imp.order, self.order) if arr.is_scalar(): return ConcreteIter(imp, 1, [], [], [], self.op_flags[i], self) if (abs(imp.strides[0]) < abs(imp.strides[-1]) and not backward) or \ diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -921,6 +921,9 @@ raises(ValueError, a.reshape, (0,), order="K") b = a.reshape((0,), order='F') assert b.shape == (0,) + a = array(range(24), 'uint8') + assert a.reshape([2, 3, 4], order=True).strides ==(1, 2, 6) + assert a.reshape([2, 3, 4], order=False).strides ==(12, 4, 1) def test_slice_reshape(self): from numpy import zeros, arange From noreply at buildbot.pypy.org Wed Sep 30 22:52:09 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 22:52:09 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: revert, do not change this file Message-ID: <20150930205209.C74D31C1F5A@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79912:e456a1c6df81 Date: 2015-09-30 23:38 +0300 http://bitbucket.org/pypy/pypy/changeset/e456a1c6df81/ Log: revert, do not change this file diff --git a/_pytest/core.py b/_pytest/core.py --- a/_pytest/core.py +++ b/_pytest/core.py @@ -175,7 +175,7 @@ continue try: plugin = ep.load() - except (DistributionNotFound, ImportError): + except DistributionNotFound: continue self._plugin_distinfo.append((ep.dist, plugin)) self.register(plugin, name=name) From noreply at buildbot.pypy.org Wed Sep 30 22:52:11 2015 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 30 Sep 2015 22:52:11 +0200 (CEST) Subject: [pypy-commit] pypy fortran-order: convert 'order' in cpyext from char to int Message-ID: <20150930205211.EF5241C1F5A@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: fortran-order Changeset: r79913:76c343105002 Date: 2015-09-30 23:52 +0300 http://bitbucket.org/pypy/pypy/changeset/76c343105002/ Log: convert 'order' in cpyext from char to int diff --git a/pypy/module/cpyext/ndarrayobject.py b/pypy/module/cpyext/ndarrayobject.py --- a/pypy/module/cpyext/ndarrayobject.py +++ b/pypy/module/cpyext/ndarrayobject.py @@ -12,6 +12,7 @@ from pypy.module.micronumpy.descriptor import get_dtype_cache, W_Dtype from pypy.module.micronumpy.concrete import ConcreteArray from pypy.module.micronumpy import ufuncs +import pypy.module.micronumpy.constants as NPY from rpython.rlib.rawstorage import RAW_STORAGE_PTR from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import W_Root @@ -203,12 +204,12 @@ return shape, dtype def simple_new(space, nd, dims, typenum, - order='C', owning=False, w_subtype=None): + order=NPY.CORDER, owning=False, w_subtype=None): shape, dtype = get_shape_and_dtype(space, nd, dims, typenum) return W_NDimArray.from_shape(space, shape, dtype) def simple_new_from_data(space, nd, dims, typenum, data, - order='C', owning=False, w_subtype=None): + order=NPY.CORDER, owning=False, w_subtype=None): shape, dtype = get_shape_and_dtype(space, nd, dims, typenum) storage = rffi.cast(RAW_STORAGE_PTR, data) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, @@ -238,7 +239,7 @@ raise OperationError(space.w_NotImplementedError, space.wrap("strides must be NULL")) - order = 'C' if flags & NPY_C_CONTIGUOUS else 'F' + order = NPY.CORDER if flags & NPY_C_CONTIGUOUS else NPY.FORTRANORDER owning = True if flags & NPY_OWNDATA else False w_subtype = None diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py b/pypy/module/cpyext/test/test_ndarrayobject.py --- a/pypy/module/cpyext/test/test_ndarrayobject.py +++ b/pypy/module/cpyext/test/test_ndarrayobject.py @@ -4,16 +4,17 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.micronumpy.ndarray import W_NDimArray from pypy.module.micronumpy.descriptor import get_dtype_cache +import pypy.module.micronumpy.constants as NPY def scalar(space): dtype = get_dtype_cache(space).w_float64dtype return W_NDimArray.new_scalar(space, dtype, space.wrap(10.)) -def array(space, shape, order='C'): +def array(space, shape, order=NPY.CORDER): dtype = get_dtype_cache(space).w_float64dtype return W_NDimArray.from_shape(space, shape, dtype, order=order) -def iarray(space, shape, order='C'): +def iarray(space, shape, order=NPY.CORDER): dtype = get_dtype_cache(space).w_int64dtype return W_NDimArray.from_shape(space, shape, dtype, order=order) @@ -32,8 +33,8 @@ def test_FLAGS(self, space, api): s = array(space, [10]) - c = array(space, [10, 5, 3], order='C') - f = array(space, [10, 5, 3], order='F') + c = array(space, [10, 5, 3], order=NPY.CORDER) + f = array(space, [10, 5, 3], order=NPY.FORTRANORDER) assert api._PyArray_FLAGS(s) & 0x0001 assert api._PyArray_FLAGS(s) & 0x0002 assert api._PyArray_FLAGS(c) & 0x0001