[pypy-commit] pypy all_ordered_dicts: OrderedDicts with the JIT: use intbounds to cache a pair "getitem /
arigo
noreply at buildbot.pypy.org
Mon Dec 22 14:51:19 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: all_ordered_dicts
Changeset: r75057:3e5bb8df5d0f
Date: 2014-12-22 14:50 +0100
http://bitbucket.org/pypy/pypy/changeset/3e5bb8df5d0f/
Log: OrderedDicts with the JIT: use intbounds to cache a pair "getitem /
setitem" on the same key.
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
@@ -6,6 +6,7 @@
from rpython.jit.metainterp.jitexc import JitException
from rpython.jit.metainterp.optimizeopt.optimizer import Optimization, MODE_ARRAY, LEVEL_KNOWNCLASS, REMOVED
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
+from rpython.jit.metainterp.optimizeopt.intutils import IntBound
from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.resoperation import rop, ResOperation
from rpython.rlib.objectmodel import we_are_translated
@@ -307,9 +308,29 @@
self.emit_operation(op)
def _optimize_CALL_DICT_LOOKUP(self, op):
+ # Cache consecutive lookup() calls on the same dict and key,
+ # depending on the 'flag_store' argument passed:
+ # FLAG_LOOKUP: always cache and use the cached result.
+ # FLAG_STORE: don't cache (it might return -1, which would be
+ # incorrect for future lookups); but if found in
+ # the cache and the cached value was already checked
+ # non-negative, then we can reuse it.
+ # FLAG_DELETE: never cache, never use the cached result (because
+ # if there is a cached result, the FLAG_DELETE call
+ # is needed for its side-effect of removing it).
+ # In theory we could cache a -1 for the case where
+ # the delete is immediately followed by a lookup,
+ # but too obscure.
+ #
from rpython.rtyper.lltypesystem.rordereddict import FLAG_LOOKUP
- if not op.getarg(4).same_box(ConstInt(FLAG_LOOKUP)):
+ from rpython.rtyper.lltypesystem.rordereddict import FLAG_STORE
+ flag_value = self.getvalue(op.getarg(4))
+ if not flag_value.is_constant():
return False
+ flag = flag_value.get_constant_int()
+ if flag != FLAG_LOOKUP and flag != FLAG_STORE:
+ return False
+ #
descrs = op.getdescr().get_extra_info().extradescrs
assert descrs # translation hint
descr1 = descrs[0]
@@ -318,13 +339,20 @@
except KeyError:
d = self.cached_dict_reads[descr1] = args_dict()
self.corresponding_array_descrs[descrs[1]] = descr1
- args = self.optimizer.make_args_key(op)
+ #
+ key = [self.optimizer.get_arg_key(op.getarg(1)), # dict
+ self.optimizer.get_arg_key(op.getarg(2))] # key
+ # other args can be ignored here (hash, store_flag)
try:
- res_v = d[args]
+ res_v = d[key]
except KeyError:
- d[args] = self.getvalue(op.result)
+ if flag == FLAG_LOOKUP:
+ d[key] = self.getvalue(op.result)
return False
else:
+ if flag != FLAG_LOOKUP:
+ if not res_v.intbound.known_ge(IntBound(0, 0)):
+ return False
self.make_equal_to(op.result, res_v)
self.last_emitted_operation = REMOVED
return True
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
@@ -221,6 +221,12 @@
if self.level < LEVEL_NONNULL:
self.level = LEVEL_NONNULL
+ def get_constant_int(self):
+ assert self.is_constant()
+ box = self.box
+ assert isinstance(box, ConstInt)
+ return box.getint()
+
def is_virtual(self):
# Don't check this with 'isinstance(_, VirtualValue)'!
# Even if it is a VirtualValue, the 'box' can be non-None,
@@ -625,18 +631,20 @@
descr.make_a_counter_per_value(op)
return op
+ def get_arg_key(self, box):
+ try:
+ value = self.values[box]
+ except KeyError:
+ pass
+ else:
+ box = value.get_key_box()
+ return box
+
def make_args_key(self, op):
n = op.numargs()
args = [None] * (n + 2)
for i in range(n):
- arg = op.getarg(i)
- try:
- value = self.values[arg]
- except KeyError:
- pass
- else:
- arg = value.get_key_box()
- args[i] = arg
+ args[i] = self.get_arg_key(op.getarg(i))
args[n] = ConstInt(op.getopnum())
args[n + 1] = op.getdescr()
return args
diff --git a/rpython/jit/metainterp/test/test_dict.py b/rpython/jit/metainterp/test/test_dict.py
--- a/rpython/jit/metainterp/test/test_dict.py
+++ b/rpython/jit/metainterp/test/test_dict.py
@@ -194,7 +194,7 @@
'guard_true': 4, 'jump': 1,
'new_with_vtable': 2, 'getinteriorfield_gc': 2,
'setfield_gc': 14, 'int_gt': 2, 'int_sub': 2,
- 'call': 10, 'int_ne': 2,
+ 'call': 10, 'int_ge': 2,
'guard_no_exception': 8, 'new': 2})
def test_unrolling_of_dict_iter(self):
@@ -297,10 +297,6 @@
self.check_simple_loop(call=7)
def test_dict_double_lookup_2(self):
- py.test.skip("xxx reimplement me")
- # one read and one write at the same key should be jitted as only
- # one lookup, but it's a bit harder now with rordereddict.py
-
driver = JitDriver(greens = [], reds = 'auto')
indexes = ['aa', 'b', 'cc']
@@ -366,7 +362,6 @@
raise Exception
self.meta_interp(f, [10])
self.check_simple_loop(call_may_force=0, call=4)
- # XXX should be call=3, same reason as test_dict_double_lookup_2
def test_dict_virtual(self):
myjitdriver = JitDriver(greens = [], reds = 'auto')
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
@@ -526,7 +526,7 @@
def ll_dict_getitem(d, key):
index = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP)
- if index != -1:
+ if index >= 0:
return d.entries[index].value
else:
raise KeyError
@@ -721,7 +721,7 @@
def ll_dict_delitem(d, key):
index = d.lookup_function(d, key, d.keyhash(key), FLAG_DELETE)
- if index == -1:
+ if index < 0:
raise KeyError
_ll_dict_del(d, index)
@@ -1024,7 +1024,7 @@
def ll_dict_get(dict, key, default):
index = dict.lookup_function(dict, key, dict.keyhash(key), FLAG_LOOKUP)
- if index == -1:
+ if index < 0:
return default
else:
return dict.entries[index].value
@@ -1032,7 +1032,7 @@
def ll_dict_setdefault(dict, key, default):
hash = dict.keyhash(key)
index = dict.lookup_function(dict, key, hash, FLAG_STORE)
- if index == -1:
+ if index < 0:
_ll_dict_setitem_lookup_done(dict, key, default, hash, -1)
return default
else:
@@ -1159,7 +1159,7 @@
def ll_dict_contains(d, key):
i = d.lookup_function(d, key, d.keyhash(key), FLAG_LOOKUP)
- return i != -1
+ return i >= 0
def _ll_getnextitem(dic):
if dic.num_live_items == 0:
@@ -1192,7 +1192,7 @@
def ll_dict_pop(dic, key):
index = dic.lookup_function(dic, key, dic.keyhash(key), FLAG_DELETE)
- if index == -1:
+ if index < 0:
raise KeyError
value = dic.entries[index].value
_ll_dict_del(dic, index)
@@ -1200,7 +1200,7 @@
def ll_dict_pop_default(dic, key, dfl):
index = dic.lookup_function(dic, key, dic.keyhash(key), FLAG_DELETE)
- if index == -1:
+ if index < 0:
return dfl
value = dic.entries[index].value
_ll_dict_del(dic, index)
More information about the pypy-commit
mailing list