[pypy-svn] r21002 - in pypy/dist/pypy/jit: . test
arigo at codespeak.net
arigo at codespeak.net
Sat Dec 10 15:37:00 CET 2005
Author: arigo
Date: Sat Dec 10 15:36:57 2005
New Revision: 21002
Modified:
pypy/dist/pypy/jit/llabstractinterp.py
pypy/dist/pypy/jit/test/test_llabstractinterp.py
Log:
Support virtual structures. Missing: support for inlined substructures and
related operations, e.g. cast_pointer.
Modified: pypy/dist/pypy/jit/llabstractinterp.py
==============================================================================
--- pypy/dist/pypy/jit/llabstractinterp.py (original)
+++ pypy/dist/pypy/jit/llabstractinterp.py Sat Dec 10 15:36:57 2005
@@ -6,6 +6,17 @@
from pypy.translator.simplify import eliminate_empty_blocks, join_blocks
+def const(value, T=None):
+ c = Constant(value)
+ c.concretetype = T or lltype.typeOf(value)
+ return c
+
+def newvar(T):
+ v = Variable()
+ v.concretetype = T
+ return v
+
+
class LLAbstractValue(object):
pass
@@ -30,17 +41,13 @@
return lltype.typeOf(self.value)
def forcevarorconst(self, builder):
- c = Constant(self.value)
- c.concretetype = self.getconcretetype()
- return c
+ return const(self.value)
def getruntimevars(self):
return []
def maybe_get_constant(self):
- c = Constant(self.value)
- c.concretetype = self.getconcretetype()
- return c
+ return const(self.value)
def with_fresh_variables(self, to_be_stored_into):
return self
@@ -81,13 +88,104 @@
return LLRuntimeValue(orig_v=to_be_stored_into)
def match(self, other):
- return isinstance(other, LLRuntimeValue) # XXX and ...
+ if isinstance(other, LLRuntimeValue):
+ if isinstance(self.copy_v, Variable):
+ return isinstance(other.copy_v, Variable)
+ else:
+ return self.copy_v == other.copy_v
+ else:
+ return False
+
+ll_no_return_value = LLRuntimeValue(const(None, lltype.Void))
+
+
+class VirtualStruct(object):
+ def __init__(self, STRUCT):
+ self.T = STRUCT
+ self.fields = {}
+
+ def getfield(self, name):
+ try:
+ return self.fields[name]
+ except KeyError:
+ T = getattr(self.T, name)
+ return LLRuntimeValue(const(T._defl()))
+
+ def setfield(self, name, value):
+ self.fields[name] = value
+
+ def copy(self):
+ result = VirtualStruct(self.T)
+ for name, a_value in self.fields.items():
+ v = newvar(a_value.getconcretetype())
+ result.fields[name] = a_value.with_fresh_variables(v)
+ return result
+
+ def force(self, builder):
+ v_result = newvar(lltype.Ptr(self.T))
+ op = SpaceOperation('malloc', [const(self.T, lltype.Void)], v_result)
+ print 'force:', op
+ builder.residual_operations.append(op)
+ # initialize all fields by relying on the assumption that the
+ # structure is initialized to zeros
+ for name in self.T._names:
+ if name in self.fields:
+ v_value = self.fields[name].forcevarorconst(builder)
+ op = SpaceOperation('setfield', [v_result,
+ const(name, lltype.Void),
+ v_value],
+ newvar(lltype.Void))
+ print 'force:', op
+ builder.residual_operations.append(op)
+ return v_result
+
+ def getruntimevars(self):
+ result = []
+ for name in self.T._names:
+ result.extend(self.getfield(name).getruntimevars())
+ return result
+
+ def match(self, other):
+ assert self.T == other.T
+ for name in self.T._names:
+ a1 = self.getfield(name)
+ a2 = other.getfield(name)
+ if not a1.match(a2):
+ return False
+ else:
+ return True
+
+
+class LLVirtualPtr(LLAbstractValue):
+
+ def __init__(self, containerobj):
+ self.containerobj = containerobj # a VirtualStruct
+
+ def getconcretetype(self):
+ return lltype.Ptr(self.containerobj.T)
+
+ def forcevarorconst(self, builder):
+ v_result = self.containerobj.force(builder)
+ self.__class__ = LLRuntimeValue
+ self.__dict__ = {'copy_v': v_result}
+ return v_result
-orig_v = Constant(None)
-orig_v.concretetype = lltype.Void
-ll_no_return_value = LLRuntimeValue(orig_v)
-del orig_v
+ def getruntimevars(self):
+ return self.containerobj.getruntimevars()
+
+ def maybe_get_constant(self):
+ return None
+
+ def with_fresh_variables(self, to_be_stored_into):
+ return LLVirtualPtr(self.containerobj.copy())
+ def match(self, other):
+ if isinstance(other, LLVirtualPtr):
+ return self.containerobj.match(other.containerobj)
+ else:
+ return False
+
+# ____________________________________________________________
class BlockState(object):
"""Entry state of a block, as a combination of LLAbstractValues
@@ -116,13 +214,12 @@
class LLAbstractInterp(object):
def __init__(self):
- self.graphs = {} # {origgraph: {BlockState: GraphState}}
+ self.graphs = []
+ self.graphstates = {} # {origgraph: {BlockState: GraphState}}
self.pendingstates = {} # {Link-or-GraphState: next-BlockState}
def itercopygraphs(self):
- for d in self.graphs.itervalues():
- for graphstate in d.itervalues():
- yield graphstate.copygraph
+ return self.graphs
def eval(self, origgraph, hints):
# for now, 'hints' means "I'm absolutely sure that the
@@ -148,9 +245,9 @@
origblock = origgraph.startblock
state, args_a = self.schedule_getstate(args_a, origblock)
try:
- graphstate = self.graphs[origgraph][state]
+ graphstate = self.graphstates[origgraph][state]
except KeyError:
- d = self.graphs.setdefault(origgraph, {})
+ d = self.graphstates.setdefault(origgraph, {})
graphstate = GraphState(self, origgraph, args_a, n=len(d))
d[state] = graphstate
self.pendingstates[graphstate] = state
@@ -192,6 +289,7 @@
self.origgraph = origgraph
name = '%s_%d' % (origgraph.name, n)
self.copygraph = FunctionGraph(name, Block([])) # grumble
+ interp.graphs.append(self.copygraph)
for orig_v, copy_v in [(origgraph.getreturnvar(),
self.copygraph.getreturnvar()),
(origgraph.exceptblock.inputargs[0],
@@ -250,8 +348,11 @@
# flow in the block
origblock = state.origblock
builder = BlockBuilder(self.interp)
+ newinputargs = []
for v, a in zip(origblock.inputargs, state.args_a):
- builder.bindings[v] = a.with_fresh_variables(to_be_stored_into=v)
+ a = a.with_fresh_variables(to_be_stored_into=v)
+ builder.bindings[v] = a
+ newinputargs.extend(a.getruntimevars())
print
# flow the actual operations of the block
for op in origblock.operations:
@@ -292,8 +393,7 @@
newlinks = [Link(args_v, target)]
#print "CLOSING"
- newblock = builder.buildblock(origblock.inputargs,
- newexitswitch, newlinks)
+ newblock = builder.buildblock(newinputargs, newexitswitch, newlinks)
state.resolveblock(newblock)
@@ -304,12 +404,8 @@
self.bindings = {} # {Variables-of-origblock: a_value}
self.residual_operations = []
- def buildblock(self, originputargs, newexitswitch, newlinks):
- inputargs = []
- for v in originputargs:
- a = self.bindings[v]
- inputargs.extend(a.getruntimevars())
- b = Block(inputargs)
+ def buildblock(self, newinputargs, newexitswitch, newlinks):
+ b = Block(newinputargs)
b.operations = self.residual_operations
b.exitswitch = newexitswitch
b.closeblock(*newlinks)
@@ -349,9 +445,7 @@
def residual(self, opname, args_a, a_result):
v_result = a_result.forcevarorconst(self)
if isinstance(v_result, Constant):
- v = Variable()
- v.concretetype = v_result.concretetype
- v_result = v
+ v_result = newvar(v_result.concretetype)
op = SpaceOperation(opname,
[a.forcevarorconst(self) for a in args_a],
v_result)
@@ -455,6 +549,10 @@
return a_result
def op_getfield(self, op, a_ptr, a_attrname):
+ if isinstance(a_ptr, LLVirtualPtr):
+ c_attrname = a_attrname.maybe_get_constant()
+ assert c_attrname is not None
+ return a_ptr.containerobj.getfield(c_attrname.value)
constant_op = None
T = a_ptr.getconcretetype().TO
if T._hints.get('immutable', False):
@@ -475,12 +573,20 @@
return self.residualize(op, [a_ptr, a_index], constant_op)
def op_malloc(self, op, a_T):
- return self.residualize(op, [a_T])
+ c_T = a_T.maybe_get_constant()
+ assert c_T is not None
+ S = VirtualStruct(c_T.value)
+ return LLVirtualPtr(S)
def op_malloc_varsize(self, op, a_T, a_size):
return self.residualize(op, [a_T, a_size])
def op_setfield(self, op, a_ptr, a_attrname, a_value):
+ if isinstance(a_ptr, LLVirtualPtr):
+ c_attrname = a_attrname.maybe_get_constant()
+ assert c_attrname is not None
+ a_ptr.containerobj.setfield(c_attrname.value, a_value)
+ return ll_no_return_value
return self.residualize(op, [a_ptr, a_attrname, a_value])
def op_setarrayitem(self, op, a_ptr, a_index, a_value):
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 Dec 10 15:36:57 2005
@@ -182,3 +182,13 @@
graph2, insns = abstrinterp(ll_function, [7], [0])
# the direct_calls are messy to count, with calls to ll_stack_check
assert insns.keys() == ['direct_call']
+
+def test_simple_malloc_removal():
+ S = lltype.GcStruct('S', ('n', lltype.Signed))
+ def ll_function(k):
+ s = lltype.malloc(S)
+ s.n = k
+ l = s.n
+ return l+1
+ graph2, insns = abstrinterp(ll_function, [7], [0])
+ assert insns == {}
More information about the Pypy-commit
mailing list