[pypy-svn] r22135 - in pypy/dist/pypy: jit jit/test rpython
arigo at codespeak.net
arigo at codespeak.net
Sat Jan 14 13:37:14 CET 2006
Author: arigo
Date: Sat Jan 14 13:37:09 2006
New Revision: 22135
Added:
pypy/dist/pypy/jit/test/test_vlist.py (contents, props changed)
pypy/dist/pypy/jit/vlist.py (contents, props changed)
Modified:
pypy/dist/pypy/jit/llabstractinterp.py
pypy/dist/pypy/jit/llcontainer.py
pypy/dist/pypy/jit/llvalue.py
pypy/dist/pypy/jit/test/test_llabstractinterp.py
pypy/dist/pypy/rpython/rlist.py
Log:
Starting LLAbstractInterp support for RPython list objects, virtualized
directly instead of as structs and arrays with multiple low-level
representations (e.g. in the presence of over-allocation).
Experimental and incomplete!
Modified: pypy/dist/pypy/jit/llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/llabstractinterp.py Sat Jan 14 13:37:09 2006
@@ -5,8 +5,10 @@
from pypy.rpython.lltypesystem import lltype
from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
from pypy.jit.llvalue import LLAbstractValue, const, newvar, dupvar
+from pypy.jit.llvalue import ll_no_return_value
from pypy.jit.llvalue import FlattenMemo, MatchMemo, FreezeMemo, UnfreezeMemo
from pypy.jit.llcontainer import LLAbstractContainer, virtualcontainervalue
+from pypy.jit.llcontainer import hasllcontent
# ____________________________________________________________
@@ -138,16 +140,16 @@
# ____________________________________________________________
-ll_no_return_value = LLAbstractValue(const(None, lltype.Void))
-
class Policy(object):
def __init__(self, inlining=False, const_propagate=False,
- concrete_propagate=True, concrete_args=True):
+ concrete_propagate=True, concrete_args=True,
+ oopspec=False):
self.inlining = inlining
self.const_propagate = const_propagate
self.concrete_propagate = concrete_propagate
self.concrete_args = concrete_args
+ self.oopspec = oopspec
# hint-driven policy
best_policy = Policy(inlining=True, const_propagate=True, concrete_args=False)
@@ -689,6 +691,13 @@
fnobj = v_func.value._obj
if not hasattr(fnobj, 'graph'):
return None
+
+ if self.interp.policy.oopspec and hasattr(fnobj._callable, 'oopspec'):
+ a_result = self.handle_highlevel_operation(op, fnobj._callable,
+ *args_a)
+ if a_result is not None:
+ return a_result
+
if getattr(fnobj._callable, 'suggested_primitive', False):
return None
@@ -745,7 +754,7 @@
return a_real_result
def op_getfield(self, op, a_ptr, a_attrname):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
c_attrname = a_attrname.maybe_get_constant()
assert c_attrname is not None
return a_ptr.content.getfield(c_attrname.value)
@@ -756,7 +765,7 @@
return self.residualize(op, [a_ptr, a_attrname], constant_op)
def op_getsubstruct(self, op, a_ptr, a_attrname):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
c_attrname = a_attrname.maybe_get_constant()
assert c_attrname is not None
# the difference with op_getfield() is only that the following
@@ -765,12 +774,12 @@
return self.residualize(op, [a_ptr, a_attrname], getattr)
def op_getarraysize(self, op, a_ptr):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
return LLAbstractValue(const(a_ptr.content.length))
return self.residualize(op, [a_ptr], len)
def op_getarrayitem(self, op, a_ptr, a_index):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
c_index = a_index.maybe_get_constant()
if c_index is not None:
return a_ptr.content.getfield(c_index.value)
@@ -794,7 +803,7 @@
return self.residualize(op, [a_T, a_size])
def op_setfield(self, op, a_ptr, a_attrname, a_value):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
c_attrname = a_attrname.maybe_get_constant()
assert c_attrname is not None
a_ptr.content.setfield(c_attrname.value, a_value)
@@ -802,7 +811,7 @@
return self.residualize(op, [a_ptr, a_attrname, a_value])
def op_setarrayitem(self, op, a_ptr, a_index, a_value):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
c_index = a_index.maybe_get_constant()
if c_index is not None:
a_ptr.content.setfield(c_index.value, a_value)
@@ -810,7 +819,7 @@
return self.residualize(op, [a_ptr, a_index, a_value])
def op_cast_pointer(self, op, a_ptr):
- if a_ptr.content is not None:
+ if hasllcontent(a_ptr):
down_or_up = lltype.castable(op.result.concretetype,
a_ptr.content.getconcretetype())
# the following works because if a structure is virtual, then
@@ -838,6 +847,50 @@
self.residual_operations.append(op)
return ll_no_return_value
+ # High-level operation dispatcher
+ def handle_highlevel_operation(self, op, ll_func, *args_a):
+ # parse the oopspec and fill in the arguments
+ operation_name, args = ll_func.oopspec.split('(', 1)
+ assert args.endswith(')')
+ args = args[:-1] + ',' # trailing comma to force tuple syntax
+ argnames = ll_func.func_code.co_varnames[:len(args_a)]
+ d = dict(zip(argnames, args_a))
+ argtuple = eval(args, d)
+ args_a = []
+ for a in argtuple:
+ if not isinstance(a, LLAbstractValue):
+ a = LLAbstractValue(const(a))
+ args_a.append(a)
+ # end of rather XXX'edly hackish parsing
+
+ if operation_name == 'newlist':
+ from pypy.jit.vlist import oop_newlist
+ handler = oop_newlist
+ else:
+ # dispatch on the 'self' argument if it is virtual
+ a_self = args_a[0]
+ args_a = args_a[1:]
+ if not isinstance(a_self, LLAbstractContainer):
+ return None
+ type_name, operation_name = operation_name.split('.')
+ if a_self.type_name != type_name:
+ return None
+ try:
+ handler = getattr(a_self, 'oop_' + operation_name)
+ except AttributeError:
+ print 'MISSING HANDLER: oop_%s' % (operation_name,)
+ return None
+ try:
+ a_result = handler(op, *args_a)
+ except NotImplementedError:
+ return None
+ if a_result is None:
+ a_result = ll_no_return_value
+ assert op.result.concretetype == a_result.getconcretetype(), (
+ "type mismatch: %s\nreturned %s\nexpected %s" % (
+ handler, a_result.getconcretetype(), op.result.concretetype))
+ return a_result
+
class InsertNextLink(Exception):
def __init__(self, link):
Modified: pypy/dist/pypy/jit/llcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/llcontainer.py (original)
+++ pypy/dist/pypy/jit/llcontainer.py Sat Jan 14 13:37:09 2006
@@ -230,3 +230,6 @@
# primitive initialized to zero
a = LLAbstractValue(const(T._defl()))
return a
+
+def hasllcontent(a_ptr):
+ return isinstance(a_ptr.content, LLVirtualContainer)
Modified: pypy/dist/pypy/jit/llvalue.py
==============================================================================
--- pypy/dist/pypy/jit/llvalue.py (original)
+++ pypy/dist/pypy/jit/llvalue.py Sat Jan 14 13:37:09 2006
@@ -24,7 +24,7 @@
def __repr__(self):
if self.runtimevar is None:
if self.content is None:
- return '<invalid!>'
+ return '<dummy>'
else:
return '<virtual %s>' % (self.content,)
else:
@@ -47,7 +47,7 @@
# don't use 'memo' here: for now, shared LLAbstractValues
# need to become distinct LLFrozenRuntimeValues.
return LLFrozenRuntimeValue(self)
- else:
+ elif self.content is not None:
# virtual container: preserve sharing
if self in memo.seen:
return memo.seen[self] # already seen
@@ -56,15 +56,21 @@
memo.seen[self] = result
result.fz_content = self.content.freeze(memo)
return result
+ else:
+ return frozen_dummy_value # dummy
def getconcretetype(self):
if self.runtimevar is not None:
return self.runtimevar.concretetype
- else:
+ elif self.content is not None:
return lltype.Ptr(self.content.T)
+ else:
+ raise ValueError("ll_dummy_value.getconcretetype()")
def forcevarorconst(self, builder):
if self.runtimevar is None:
+ if self.content is None:
+ raise ValueError("ll_dummy_value.forcevarorconst()")
self.runtimevar = self.content.build_runtime_container(builder)
self.content = None
return self.runtimevar
@@ -83,10 +89,12 @@
if not self.concrete: # skip concrete values, they don't need
# to be present in the residual graph at all
memo.result.append(self)
- else:
+ elif self.content is not None:
if self not in memo.seen:
memo.seen[self] = True
self.content.flatten(memo)
+ else:
+ pass # dummy
# ____________________________________________________________
@@ -99,6 +107,18 @@
# relevant in the finished block.
+class LLFrozenDummyValue(LLFrozenValue):
+
+ def flatten(self, memo):
+ pass
+
+ def unfreeze(self, memo):
+ return ll_dummy_value
+
+ def match(self, a_value, memo):
+ return True # a dummy matches anything
+
+
class LLFrozenConcreteValue(LLFrozenValue):
def __init__(self, a_source):
@@ -236,3 +256,7 @@
v1 = Variable(v)
v1.concretetype = v.concretetype
return v1
+
+ll_no_return_value = LLAbstractValue(const(None, lltype.Void))
+ll_dummy_value = LLAbstractValue()
+frozen_dummy_value = LLFrozenDummyValue()
Modified: pypy/dist/pypy/jit/test/test_llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/test/test_llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/test/test_llabstractinterp.py Sat Jan 14 13:37:09 2006
@@ -54,13 +54,16 @@
result1 = llinterp.eval_graph(graph1, argvalues)
result2 = llinterp.eval_graph(graph2, argvalues2)
assert result1 == result2
- # return a summary of the instructions left in graph2
+ return graph2, summary(interp)
+
+def summary(interp):
+ # return a summary of the instructions left in all the residual graphs
insns = {}
for copygraph in interp.itercopygraphs():
for block in copygraph.iterblocks():
for op in block.operations:
insns[op.opname] = insns.get(op.opname, 0) + 1
- return graph2, insns
+ return insns
P_INLINE = Policy(inlining=True)
P_CONST_INLINE = Policy(inlining=True, const_propagate=True)
Added: pypy/dist/pypy/jit/test/test_vlist.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/jit/test/test_vlist.py Sat Jan 14 13:37:09 2006
@@ -0,0 +1,45 @@
+import py
+from pypy.translator.translator import TranslationContext
+from pypy.jit.llabstractinterp import LLAbstractInterp, Policy
+from pypy.jit.test.test_llabstractinterp import summary
+from pypy.rpython.llinterp import LLInterpreter
+from pypy.rpython.rstr import string_repr
+from pypy.rpython.objectmodel import hint
+
+policy = Policy(inlining=True, const_propagate=True, concrete_args=False,
+ oopspec=True)
+
+def run(fn, argvalues):
+ t = TranslationContext()
+ t.buildannotator().build_types(fn, [type(x) for x in argvalues])
+ rtyper = t.buildrtyper()
+ rtyper.specialize()
+ graph1 = t.graphs[0]
+
+ interp = LLAbstractInterp(policy)
+ hints = {}
+ llvalues = []
+ for i, value in enumerate(argvalues):
+ if isinstance(value, str):
+ value = string_repr.convert_const(value)
+ llvalues.append(value)
+ hints[i] = value
+ graph2 = interp.eval(graph1, hints)
+ #graph2.show()
+
+ llinterp = LLInterpreter(rtyper)
+ result1 = llinterp.eval_graph(graph1, llvalues)
+ result2 = llinterp.eval_graph(graph2, [])
+
+ assert result1 == result2
+
+ return graph2, summary(interp)
+
+
+def test_newlist():
+ py.test.skip("in-progress")
+ def fn(n):
+ lst = [5] * n
+ return len(lst)
+ graph2, insns = run(fn, [12])
+ assert insns == {}
Added: pypy/dist/pypy/jit/vlist.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/jit/vlist.py Sat Jan 14 13:37:09 2006
@@ -0,0 +1,83 @@
+from pypy.rpython.lltypesystem import lltype
+from pypy.jit.llvalue import LLAbstractValue, newvar, const, ll_dummy_value
+from pypy.jit.llcontainer import LLAbstractContainer
+
+
+class LLVirtualList(LLAbstractContainer):
+ type_name = 'list'
+
+ def __init__(self, T, items_a=None):
+ self.T = T
+ if items_a is None:
+ self.items_a = []
+ else:
+ self.items_a = items_a
+
+ def flatten(self, memo):
+ assert self not in memo.seen; memo.seen[self] = True # debugging only
+ for a_value in self.items_a:
+ a_value.flatten(memo)
+
+ def match(self, live, memo):
+ if self.__class__ is not live.__class__:
+ return False
+ if len(self.items_a) != len(live.items_a):
+ return False
+ for a1, a2 in zip(self.items_a, live.items_a):
+ if not a1.match(a2, memo):
+ return False
+ else:
+ return True
+
+ def freeze(self, memo):
+ items_a = [a.freeze(memo) for a in self.items_a]
+ return LLVirtualList(self.T, items_a)
+
+ def unfreeze(self, memo):
+ items_a = [a.unfreeze(memo) for a in self.items_a]
+ return LLVirtualList(self.T, items_a)
+
+ def build_runtime_container(self, builder):
+ cno = const(len(self.items_a))
+ v_result = builder.gendirectcall(self.T.ll_newlist, cno)
+ cdum = const(rlist.dum_nocheck, lltype.Void)
+ for i, a in enumerate(self.items_a):
+ ci = const(i)
+ v_item = a.forcevarorconst(builder)
+ builder.gendirectcall(rlist.ll_setitem_nonneg,
+ cdum, v_result, ci, v_item)
+ return v_result
+
+ # ____________________________________________________________
+ # High-level operations
+
+ def oop_getitem(self, op, a_index):
+ c_index = a_index.maybe_get_constant()
+ if c_index is None:
+ raise NotImplementedError
+ return self.items_a[c_index.value]
+
+ def oop_setitem(self, op, a_index, a_newobj):
+ c_index = a_index.maybe_get_constant()
+ if c_index is None:
+ raise NotImplementedError
+ self.items_a[c_index.value] = a_newobj
+
+ def oop_append(self, op, a_newobj):
+ self.items_a.append(a_newobj)
+
+ def oop_pop(self, op, a_index):
+ c_index = a_index.maybe_get_constant()
+ if c_index is None:
+ raise NotImplementedError
+ return self.items_a.pop(c_index.value)
+
+
+def oop_newlist(op, a_numitems):
+ c_numitems = a_numitems.maybe_get_constant()
+ if c_numitems is None:
+ raise NotImplementedError
+ LIST = op.result.concretetype.TO
+ items_a = [ll_dummy_value] * c_numitems.value
+ virtuallist = LLVirtualList(LIST, items_a)
+ return LLAbstractValue(content=virtuallist)
Modified: pypy/dist/pypy/rpython/rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/rlist.py (original)
+++ pypy/dist/pypy/rpython/rlist.py Sat Jan 14 13:37:09 2006
@@ -558,6 +558,7 @@
items[newlength] = nullptr(ITEM.TO)
_ll_list_resize_le(l, newlength)
return res
+ll_pop_zero.oopspec = 'list.pop(l, 0)'
def ll_pop(func, l, index):
length = l.length
@@ -861,6 +862,7 @@
l.items = malloc(LIST.items.TO, length)
return l
ll_newlist = typeMethod(ll_newlist)
+ll_newlist.oopspec = 'newlist(length)'
def ll_length(l):
return l.length
@@ -874,6 +876,7 @@
l = malloc(LIST, length)
return l
ll_fixed_newlist = typeMethod(ll_fixed_newlist)
+ll_fixed_newlist.oopspec = 'newlist(length)'
def ll_fixed_length(l):
return len(l)
More information about the Pypy-commit
mailing list