[pypy-svn] r25977 - in pypy/dist/pypy: rpython/rctypes/test translator/backendopt translator/backendopt/test
arigo at codespeak.net
arigo at codespeak.net
Wed Apr 19 13:17:41 CEST 2006
Author: arigo
Date: Wed Apr 19 13:17:40 2006
New Revision: 25977
Modified:
pypy/dist/pypy/rpython/rctypes/test/test_overhead.py
pypy/dist/pypy/translator/backendopt/malloc.py
pypy/dist/pypy/translator/backendopt/test/test_malloc.py
Log:
direct_fieldptr support in malloc removal, for rctypes.
The code is getting rather involved, but still has some
kind of convoluted elegance to it.
Modified: pypy/dist/pypy/rpython/rctypes/test/test_overhead.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_overhead.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_overhead.py Wed Apr 19 13:17:40 2006
@@ -81,7 +81,6 @@
assert not mallocs
def test_struct_setitem():
- py.test.skip("not working yet")
class S(Structure):
_fields_ = [('x', c_int)]
class T(Structure):
Modified: pypy/dist/pypy/translator/backendopt/malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/malloc.py (original)
+++ pypy/dist/pypy/translator/backendopt/malloc.py Wed Apr 19 13:17:40 2006
@@ -23,8 +23,8 @@
# we consider a pointer to a GcStruct S as equivalent to a
# pointer to a substructure 'S.fieldname' if it's the first
# inlined sub-GcStruct. As an extension we also allow a pointer
- # to a GcStruct containing just one Struct to be equivalent to
- # a pointer to that Struct only (although a mere cast_pointer
+ # to a GcStruct containing just one field to be equivalent to
+ # a pointer to that field only (although a mere cast_pointer
# would not allow casting). This is needed to malloc-remove
# the 'wrapper' GcStructs introduced by previous passes of
# malloc removal.
@@ -35,7 +35,7 @@
FIELDTYPE = S._flds[fieldname]
if isinstance(FIELDTYPE, lltype.GcStruct):
return True
- if len(S._names) == 1 and isinstance(FIELDTYPE, lltype.Struct):
+ if len(S._names) == 1:
return True
return False
@@ -79,7 +79,7 @@
# and output variables
union(node, op.args[0], node, op.result)
continue
- if op.opname == 'getsubstruct':
+ if op.opname in ('getsubstruct', 'direct_fieldptr'):
S = op.args[0].concretetype.TO
if equivalent_substruct(S, op.args[1].value):
# assumed to be similar to a cast_pointer
@@ -135,26 +135,42 @@
STRUCT = lltypes.keys()[0].TO
assert isinstance(STRUCT, lltype.GcStruct)
- # must be only ever accessed via getfield/setfield/getsubstruct
- # or touched by keepalive. Note that same_as and cast_pointer
- # are not recorded in usepoints.
- VALID = dict.fromkeys([("getfield", 0),
- ("setfield", 0),
- ("getsubstruct", 0),
- ("keepalive", 0)])
- MAYBE_VALID = dict.fromkeys([("getarrayitem", 0),
- ("setarrayitem", 0),
- ("getarraysubstruct", 0)])
+ # must be only ever accessed via getfield/setfield/getsubstruct/
+ # direct_fieldptr, or touched by keepalive. Note that same_as and
+ # cast_pointer are not recorded in usepoints.
+ FIELD_ACCESS = dict.fromkeys(["getfield",
+ "setfield",
+ "keepalive",
+ "getarrayitem",
+ "setarrayitem"])
+ SUBSTRUCT_ACCESS = dict.fromkeys(["getsubstruct",
+ "direct_fieldptr",
+ "getarraysubstruct"])
+
+ CHECK_ARRAY_INDEX = dict.fromkeys(["getarrayitem",
+ "setarrayitem",
+ "getarraysubstruct"])
+ accessed_substructs = {}
+
for up in info.usepoints:
if up[0] != "op":
return False
kind, node, op, index = up
- if (op.opname, index) in VALID:
- continue # ok
- if (op.opname, index) in MAYBE_VALID:
- if isinstance(op.args[1], Constant):
- continue # ok if the index is constant
- return False
+ if index != 0:
+ return False
+ if op.opname in CHECK_ARRAY_INDEX:
+ if not isinstance(op.args[1], Constant):
+ return False # non-constant array index
+ if op.opname in FIELD_ACCESS:
+ pass # ok
+ elif op.opname in SUBSTRUCT_ACCESS:
+ S = op.args[0].concretetype.TO
+ name = op.args[1].value
+ if not isinstance(name, str): # access by index
+ name = 'item%d' % (name,)
+ accessed_substructs[S, name] = True
+ else:
+ return False
# must not remove mallocs of structures that have a RTTI with a destructor
@@ -165,16 +181,7 @@
except (ValueError, AttributeError), e:
pass
- # to avoid an infinite loop of "removals" without actual progress,
- # be careful when trying to remove something that already looks like
- # a GcStruct wrapper
- if (len(STRUCT._names) == 1 and
- isinstance(STRUCT._flds[STRUCT._names[0]], lltype.ContainerType) and
- not equivalent_substruct(STRUCT, STRUCT._names[0])):
- return False
-
# success: replace each variable with a family of variables (one per field)
- example = STRUCT._container_example()
# 'flatnames' is a list of (STRUCTTYPE, fieldname_in_that_struct) that
# describes the list of variables that should replace the single
@@ -191,27 +198,47 @@
flatconstants = {}
needsubmallocs = []
newvarstype = {} # map {item-of-flatnames: concretetype}
+ direct_fieldptr_key = {}
- def flatten(S, example):
+ def flatten(S):
start = 0
if S._names and equivalent_substruct(S, S._names[0]):
- flatten(S._flds[S._names[0]], getattr(example, S._names[0]))
- start = 1
+ SUBTYPE = S._flds[S._names[0]]
+ if isinstance(SUBTYPE, lltype.Struct):
+ flatten(SUBTYPE)
+ start = 1
+ else:
+ ARRAY = lltype.FixedSizeArray(SUBTYPE, 1)
+ direct_fieldptr_key[ARRAY, 'item0'] = S, S._names[0]
for name in S._names[start:]:
key = S, name
flatnames.append(key)
FIELDTYPE = S._flds[name]
- if isinstance(FIELDTYPE, lltype.ContainerType):
+ if key in accessed_substructs:
needsubmallocs.append(key)
newvarstype[key] = lltype.Ptr(lltype.GcStruct('wrapper',
('data', FIELDTYPE)))
- else:
- constant = Constant(getattr(example, name))
+ elif not isinstance(FIELDTYPE, lltype.ContainerType):
+ example = FIELDTYPE._defl()
+ constant = Constant(example)
constant.concretetype = FIELDTYPE
flatconstants[key] = constant
newvarstype[key] = FIELDTYPE
+ #else:
+ # the inlined substructure is never accessed, drop it
+
+ flatten(STRUCT)
+ assert len(direct_fieldptr_key) <= 1
- flatten(STRUCT, example)
+ def key_for_field_access(S, fldname):
+ if isinstance(S, lltype.FixedSizeArray):
+ if not isinstance(fldname, str): # access by index
+ fldname = 'item%d' % (fldname,)
+ try:
+ return direct_fieldptr_key[S, fldname]
+ except KeyError:
+ pass
+ return S, fldname
variables_by_block = {}
for block, var in info.variables:
@@ -241,20 +268,31 @@
if op.opname in ("getfield", "getarrayitem"):
S = op.args[0].concretetype.TO
fldname = op.args[1].value
- if op.opname == "getarrayitem":
- fldname = 'item%d' % fldname
- newop = SpaceOperation("same_as",
- [newvarsmap[S, fldname]],
- op.result)
+ key = key_for_field_access(S, fldname)
+ if key in accessed_substructs:
+ c_name = Constant('data', lltype.Void)
+ newop = SpaceOperation("getfield",
+ [newvarsmap[key], c_name],
+ op.result)
+ else:
+ newop = SpaceOperation("same_as",
+ [newvarsmap[key]],
+ op.result)
newops.append(newop)
last_removed_access = len(newops)
elif op.opname in ("setfield", "setarrayitem"):
S = op.args[0].concretetype.TO
fldname = op.args[1].value
- if op.opname == "setarrayitem":
- fldname = 'item%d' % fldname
- assert (S, fldname) in newvarsmap
- newvarsmap[S, fldname] = op.args[2]
+ key = key_for_field_access(S, fldname)
+ assert key in newvarsmap
+ if key in accessed_substructs:
+ c_name = Constant('data', lltype.Void)
+ newop = SpaceOperation("setfield",
+ [newvarsmap[key], c_name, op.args[2]],
+ op.result)
+ newops.append(newop)
+ else:
+ newvarsmap[key] = op.args[2]
last_removed_access = len(newops)
elif op.opname in ("same_as", "cast_pointer"):
assert op.result not in vars
@@ -265,7 +303,8 @@
# via one pointer must be reflected in the other.
elif op.opname == 'keepalive':
last_removed_access = len(newops)
- elif op.opname in ("getsubstruct", "getarraysubstruct"):
+ elif op.opname in ("getsubstruct", "getarraysubstruct",
+ "direct_fieldptr"):
S = op.args[0].concretetype.TO
fldname = op.args[1].value
if op.opname == "getarraysubstruct":
@@ -278,9 +317,13 @@
else:
# do it with a getsubstruct on the independently
# malloc'ed GcStruct
+ if op.opname == "direct_fieldptr":
+ opname = "direct_fieldptr"
+ else:
+ opname = "getsubstruct"
v = newvarsmap[S, fldname]
cname = Constant('data', lltype.Void)
- newop = SpaceOperation("getsubstruct",
+ newop = SpaceOperation(opname,
[v, cname],
op.result)
newops.append(newop)
@@ -289,7 +332,7 @@
elif op.result in vars:
assert op.opname == "malloc"
assert vars == {var: True}
- count[0] += 1
+ progress = True
# drop the "malloc" operation
newvarsmap = flatconstants.copy() # zero initial values
# if there are substructures, they are now individually
@@ -299,9 +342,13 @@
v = Variable()
v.concretetype = newvarstype[key]
c = Constant(v.concretetype.TO, lltype.Void)
+ if c.value == op.args[0].value:
+ progress = False # replacing a malloc with
+ # the same malloc!
newop = SpaceOperation("malloc", [c], v)
newops.append(newop)
newvarsmap[key] = v
+ count[0] += progress
else:
newops.append(op)
@@ -354,7 +401,6 @@
for var in vars_created_here:
flowin(var, newvarsmap=None)
- assert count[0]
return count[0]
def remove_mallocs_once(graph):
Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_malloc.py (original)
+++ pypy/dist/pypy/translator/backendopt/test/test_malloc.py Wed Apr 19 13:17:40 2006
@@ -209,3 +209,46 @@
g(b.s)
check(fn, [], [], None, must_be_removed=False)
+
+def test_direct_fieldptr():
+ from pypy.rpython.lltypesystem import lltype
+ S = lltype.GcStruct('S', ('x', lltype.Signed))
+
+ def fn():
+ s = lltype.malloc(S)
+ s.x = 11
+ p = lltype.direct_fieldptr(s, 'x')
+ return p[0]
+
+ check(fn, [], [], 11)
+
+def test_direct_fieldptr_2():
+ from pypy.rpython.lltypesystem import lltype
+ T = lltype.GcStruct('T', ('z', lltype.Signed))
+ S = lltype.GcStruct('S', ('t', T),
+ ('x', lltype.Signed),
+ ('y', lltype.Signed))
+ def fn():
+ s = lltype.malloc(S)
+ s.x = 10
+ s.t.z = 1
+ px = lltype.direct_fieldptr(s, 'x')
+ py = lltype.direct_fieldptr(s, 'y')
+ pz = lltype.direct_fieldptr(s.t, 'z')
+ py[0] = 31
+ return px[0] + s.y + pz[0]
+
+ check(fn, [], [], 42)
+
+def test_getarraysubstruct():
+ from pypy.rpython.lltypesystem import lltype
+ U = lltype.Struct('U', ('n', lltype.Signed))
+ for length in [1, 2]:
+ S = lltype.GcStruct('S', ('a', lltype.FixedSizeArray(U, length)))
+ for index in range(length):
+
+ def fn():
+ s = lltype.malloc(S)
+ s.a[index].n = 12
+ return s.a[index].n
+ check(fn, [], [], 12)
More information about the Pypy-commit
mailing list