[pypy-svn] r13830 - in pypy/dist/pypy: annotation rpython rpython/test translator
hpk at codespeak.net
hpk at codespeak.net
Fri Jun 24 21:13:39 CEST 2005
Author: hpk
Date: Fri Jun 24 21:13:35 2005
New Revision: 13830
Modified:
pypy/dist/pypy/annotation/bookkeeper.py
pypy/dist/pypy/annotation/specialize.py
pypy/dist/pypy/rpython/normalizecalls.py
pypy/dist/pypy/rpython/rpbc.py
pypy/dist/pypy/rpython/rtyper.py
pypy/dist/pypy/rpython/test/test_llinterp.py
pypy/dist/pypy/rpython/test/test_rpbc.py
pypy/dist/pypy/translator/transform.py
Log:
(arigo, hpk with special consulting by pedronis)
- support for specialcase:memo functions (like the often
used pypy.tool.cache.Cache.getorbuild function).
Currently, only one PBC argument is allowed for such
functions. Somewhat unfortunately, the support is
spread across a number of files but it works and
doesn't really involve a large number of lines.
Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py (original)
+++ pypy/dist/pypy/annotation/bookkeeper.py Fri Jun 24 21:13:35 2005
@@ -24,6 +24,7 @@
self.objects = { obj: True }
self.read_locations = {}
self.attrs = {}
+ self.values = {} # used in the typer
def update(self, other):
self.objects.update(other.objects)
@@ -193,6 +194,8 @@
self.pbc_call_sites = {}
+ self.memo_tables = []
+
self.stats = Stats(self)
# import ordering hack
Modified: pypy/dist/pypy/annotation/specialize.py
==============================================================================
--- pypy/dist/pypy/annotation/specialize.py (original)
+++ pypy/dist/pypy/annotation/specialize.py Fri Jun 24 21:13:35 2005
@@ -126,6 +126,18 @@
# ____________________________________________________________________________
# specializations
+class MemoTable:
+ def __init__(self, bookkeeper, func, s_result, arglist_s):
+ self.table = {}
+ self.arglist_s = arglist_s
+ self.s_result = s_result
+ for arglist in possible_arguments(arglist_s):
+ result = func(*arglist)
+ self.table[arglist] = result
+ bookkeeper.memo_tables.append(self)
+ def _freeze_(self):
+ return True
+
def memo(bookkeeper, mod, spaceop, func, args, mono):
"""NOT_RPYTHON"""
assert mono, "not-static call to memoized %s" % func
@@ -140,28 +152,32 @@
possible_results.append(bookkeeper.immutablevalue(result))
return unionof(*possible_results), args
-def possible_arguments(args):
+def possible_values_of(s):
from pypy.annotation.model import SomeBool, SomePBC
- # enumerate all tuples (x1,..xn) of concrete values that are contained
- # in a tuple args=(s1,..sn) of SomeXxx. Requires that each s be either
- # a constant or SomePBC.
- if not args:
- yield ()
- return
- s = args[0]
if s.is_constant():
- possible_values = [s.const]
+ return [s.const]
elif isinstance(s, SomePBC):
for value in s.prebuiltinstances.values():
assert value is True, ("concrete call with a method bound "
"on a non-constant instance")
- possible_values = s.prebuiltinstances.keys()
+ return s.prebuiltinstances.keys()
elif isinstance(s, SomeBool):
- possible_values = [False, True]
+ return [False, True]
else:
- raise AssertionError, "concrete call with a non-constant arg %r" % (s,)
- for tuple_tail in possible_arguments(args[1:]):
- for value in possible_values:
+ raise ValueError, "memo call with a non-constant arg %r" % (s,)
+
+def possible_arguments(args):
+ # enumerate all tuples (x1,..xn) of concrete values that are contained
+ # in a tuple args=(s1,..sn) of SomeXxx. Requires that each s be either
+ # a constant or SomePBC.
+ return cartesian_product([possible_values_of(s) for s in args])
+
+def cartesian_product(lstlst):
+ if not lstlst:
+ yield ()
+ return
+ for tuple_tail in cartesian_product(lstlst[1:]):
+ for value in lstlst[0]:
yield (value,) + tuple_tail
#def argtypes(bookkeeper, spaceop, func, args, mono):
Modified: pypy/dist/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/dist/pypy/rpython/normalizecalls.py (original)
+++ pypy/dist/pypy/rpython/normalizecalls.py Fri Jun 24 21:13:35 2005
@@ -165,9 +165,43 @@
annotator.setbinding(graph.getreturnvar(), generalizedresult)
+def specialize_pbcs_by_memotables(annotator):
+ memo_tables = annotator.bookkeeper.memo_tables
+ access_sets = annotator.getpbcaccesssets()
+ for memo_table in memo_tables:
+ arglist_s = memo_table.arglist_s
+ assert len(arglist_s) == 1, "XXX implement >1 arguments"
+ arg1 = arglist_s[0]
+ assert isinstance(arg1, annmodel.SomePBC)
+
+ if None in arg1.prebuiltinstances:
+ raise TyperError("unsupported: memo call with an argument that can be None")
+ pbcs = arg1.prebuiltinstances.keys()
+ _, _, access_set = access_sets.find(pbcs[0])
+
+ # enforce a structure where we can uniformly access
+ # our memofield later
+ for pbc in pbcs[1:]:
+ _, _, access_set = access_sets.union(pbcs[0], pbc)
+
+ # we can have multiple memo_tables per PBC
+ i = 0
+ while 1:
+ fieldname = "memofield_%d" % i
+ if fieldname in access_set.attrs:
+ i += 1
+ continue
+ memo_table.fieldname = fieldname
+ break
+ access_set.attrs[fieldname] = memo_table.s_result
+ for pbc in pbcs:
+ value = memo_table.table[(pbc,)]
+ access_set.values[(pbc, fieldname)] = value
+
def perform_normalizations(annotator):
annotator.frozen += 1
try:
normalize_function_signatures(annotator)
+ specialize_pbcs_by_memotables(annotator)
finally:
annotator.frozen -= 1
Modified: pypy/dist/pypy/rpython/rpbc.py
==============================================================================
--- pypy/dist/pypy/rpython/rpbc.py (original)
+++ pypy/dist/pypy/rpython/rpbc.py Fri Jun 24 21:13:35 2005
@@ -5,7 +5,7 @@
from pypy.objspace.flow.model import Constant
from pypy.rpython.lltype import typeOf, Void, ForwardReference, Struct, Bool
from pypy.rpython.lltype import Ptr, malloc, nullptr
-from pypy.rpython.rmodel import Repr, TyperError
+from pypy.rpython.rmodel import Repr, TyperError, inputconst
from pypy.rpython import rclass
from pypy.rpython.rtyper import HighLevelOp
@@ -166,7 +166,10 @@
result = malloc(self.pbc_type, immortal=True)
self.pbc_cache[pbc] = result
for attr, (mangled_name, r_value) in self.llfieldmap.items():
- thisattrvalue = getattr(pbc, attr)
+ try:
+ thisattrvalue = self.access_set.values[(pbc, attr)]
+ except KeyError:
+ thisattrvalue = getattr(pbc, attr)
llvalue = r_value.convert_const(thisattrvalue)
setattr(result, mangled_name, llvalue)
return result
@@ -174,10 +177,13 @@
def rtype_getattr(self, hop):
attr = hop.args_s[1].const
vpbc, vattr = hop.inputargs(self, Void)
+ return self.getfield(vpbc, attr, hop.llops)
+
+ def getfield(self, vpbc, attr, llops):
mangled_name, r_value = self.llfieldmap[attr]
- cmangledname = hop.inputconst(Void, mangled_name)
- return hop.genop('getfield', [vpbc, cmangledname],
- resulttype = r_value)
+ cmangledname = inputconst(Void, mangled_name)
+ return llops.genop('getfield', [vpbc, cmangledname],
+ resulttype = r_value)
# ____________________________________________________________
@@ -424,3 +430,15 @@
# now hop2 looks like simple_call(initfunc, instance, args...)
hop2.dispatch()
return v_instance
+
+# ____________________________________________________________
+
+def rtype_call_memo(hop):
+ memo_table = hop.args_v[0].value
+ fieldname = memo_table.fieldname
+ assert hop.nb_args == 2, "XXX"
+
+ r_pbc = hop.args_r[1]
+ assert isinstance(r_pbc, MultipleFrozenPBCRepr)
+ v_table, v_pbc = hop.inputargs(Void, r_pbc)
+ return r_pbc.getfield(v_pbc, fieldname, hop.llops)
Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py (original)
+++ pypy/dist/pypy/rpython/rtyper.py Fri Jun 24 21:13:35 2005
@@ -352,6 +352,9 @@
def translate_op_newslice(self, hop):
return rslice.rtype_newslice(hop)
+ def translate_op_call_memo(self, hop):
+ return rpbc.rtype_call_memo(hop)
+
def missing_operation(self, hop):
raise TyperError("unimplemented operation: '%s'" % hop.spaceop.opname)
Modified: pypy/dist/pypy/rpython/test/test_llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_llinterp.py (original)
+++ pypy/dist/pypy/rpython/test/test_llinterp.py Fri Jun 24 21:13:35 2005
@@ -31,6 +31,7 @@
t = Translator(func)
t.annotate(argtypes)
if viewbefore:
+ t.annotator.simplify()
t.view()
global typer # we need it for find_exception
typer = RPythonTyper(t.annotator)
@@ -40,8 +41,8 @@
return t, typer
def interpret(func, values, view=False, viewbefore=False):
- t, typer = gengraph(func, [lltype_to_annotation(typeOf(x)) for x in values],
- viewbefore)
+ t, typer = gengraph(func, [lltype_to_annotation(typeOf(x))
+ for x in values], viewbefore)
if view:
t.view()
interp = LLInterpreter(t.flowgraphs, typer)
@@ -49,8 +50,8 @@
return res
def make_interpreter(func, example_values, view=False, viewbefore=False):
- t, typer = gengraph(func, [lltype_to_annotation(typeOf(x)) for x in example_values],
- viewbefore)
+ t, typer = gengraph(func, [lltype_to_annotation(typeOf(x))
+ for x in example_values], viewbefore)
if view:
t.view()
interp = LLInterpreter(t.flowgraphs, typer)
Modified: pypy/dist/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rpbc.py (original)
+++ pypy/dist/pypy/rpython/test/test_rpbc.py Fri Jun 24 21:13:35 2005
@@ -1,7 +1,7 @@
from pypy.translator.translator import Translator
from pypy.rpython.lltype import *
from pypy.rpython.rtyper import RPythonTyper
-from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.test.test_llinterp import interpret, make_interpreter
def test_easy_call():
@@ -143,3 +143,31 @@
assert res == 1+10+3
res = interpret(f3, [])
assert res == 1+10+100
+
+def test_call_memoized():
+ fr1 = Freezing()
+ fr1.x = 0
+ fr2 = Freezing()
+ fr2.x = 1
+ def getorbuild(key):
+ a = 1
+ if key is fr1:
+ result = eval("a+2")
+ else:
+ result = eval("a+6")
+ return result
+ getorbuild._annspecialcase_ = "specialize:memo"
+
+ def f1(i):
+ if i > 0:
+ fr = fr1
+ else:
+ fr = fr2
+ # XXX this should work without fr.x
+ return getorbuild(fr) + fr.x
+
+ ev_f1 = make_interpreter(f1, [0])#, viewbefore=True)
+ res = ev_f1(0)
+ assert res == 8
+ res = ev_f1(1)
+ assert res == 3
Modified: pypy/dist/pypy/translator/transform.py
==============================================================================
--- pypy/dist/pypy/translator/transform.py (original)
+++ pypy/dist/pypy/translator/transform.py Fri Jun 24 21:13:35 2005
@@ -13,6 +13,7 @@
from pypy.objspace.flow.model import last_exception
from pypy.translator.annrpython import CannotSimplify
from pypy.annotation import model as annmodel
+from pypy.annotation.specialize import MemoTable
def fully_annotated_blocks(self):
"""Ignore blocked blocks."""
@@ -152,10 +153,20 @@
if not specialcase:
op.args[0] = Constant(specialized_callb.prebuiltinstances.keys()[0])
else:
- if op.opname == 'simple_call':
- op.opname = intern('simple_specialcase')
+ if op.opname != 'simple_call':
+ assert 0, "not supported: call_args to a specialized function"
+ callable = callb.prebuiltinstances.keys()[0]
+ tag = getattr(callable, '_annspecialcase_', None)
+ if tag == 'specialize:memo':
+ arglist_s = [self.binding(v) for v in op.args[1:]]
+ memo_table = MemoTable(self.bookkeeper,
+ callable,
+ self.binding(op.result),
+ arglist_s)
+ op.opname = intern('call_memo')
+ op.args[0] = Constant(memo_table)
else:
- op.opname = intern('specialcase_args')
+ op.opname = intern('call_specialcase')
default_extra_passes = [
transform_specialization,
More information about the Pypy-commit
mailing list