[pypy-svn] r31256 - in pypy/dist/pypy: rpython/rctypes rpython/rctypes/test translator/backendopt translator/backendopt/test translator/c translator/c/test
arigo at codespeak.net
arigo at codespeak.net
Fri Aug 11 12:54:45 CEST 2006
Author: arigo
Date: Fri Aug 11 12:54:43 2006
New Revision: 31256
Modified:
pypy/dist/pypy/rpython/rctypes/astruct.py
pypy/dist/pypy/rpython/rctypes/rstruct.py
pypy/dist/pypy/rpython/rctypes/test/test_rstruct.py
pypy/dist/pypy/translator/backendopt/malloc.py
pypy/dist/pypy/translator/backendopt/test/test_malloc.py
pypy/dist/pypy/translator/c/genc.py
pypy/dist/pypy/translator/c/node.py
pypy/dist/pypy/translator/c/test/test_lltyped.py
Log:
Support for ctypes.Union in genc. (XXX missing llinterp support)
Modified: pypy/dist/pypy/rpython/rctypes/astruct.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/astruct.py (original)
+++ pypy/dist/pypy/rpython/rctypes/astruct.py Fri Aug 11 12:54:43 2006
@@ -1,14 +1,18 @@
-from ctypes import Structure
+from ctypes import Structure, Union
from pypy.annotation.model import SomeCTypesObject
from pypy.rpython.rctypes.implementation import CTypesCallEntry, CTypesObjEntry
from pypy.rpython.lltypesystem import lltype
StructType = type(Structure)
+UnionType = type(Union)
+
+# XXX this also implements Unions, but they are not properly emulated
+# by the llinterpreter. They work in the generated C code, though.
class CallEntry(CTypesCallEntry):
"Annotation and rtyping of calls to structure types."
- _type_ = StructType
+ _type_ = StructType, UnionType
def specialize_call(self, hop, **kwds_i):
from pypy.rpython.error import TyperError
@@ -48,7 +52,7 @@
class ObjEntry(CTypesObjEntry):
"Annotation and rtyping of structure instances."
- _metatype_ = StructType
+ _metatype_ = StructType, UnionType
def get_field_annotation(self, s_struct, fieldname):
for name, ctype in self.type._fields_:
@@ -59,4 +63,7 @@
def get_repr(self, rtyper, s_struct):
from pypy.rpython.rctypes.rstruct import StructRepr
- return StructRepr(rtyper, s_struct)
+ is_struct = isinstance(self.type, StructType)
+ is_union = isinstance(self.type, UnionType)
+ assert is_struct ^ is_union
+ return StructRepr(rtyper, s_struct, is_union)
Modified: pypy/dist/pypy/rpython/rctypes/rstruct.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rstruct.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rstruct.py Fri Aug 11 12:54:43 2006
@@ -7,7 +7,7 @@
class StructRepr(CTypesRefRepr):
- def __init__(self, rtyper, s_struct):
+ def __init__(self, rtyper, s_struct, is_union=False):
struct_ctype = s_struct.knowntype
# Find the repr and low-level type of the fields from their ctype
@@ -23,6 +23,8 @@
external = getattr(struct_ctype, '_external_', False)
extras = {'hints': {'c_name': struct_ctype.__name__,
'external': external}}
+ if is_union:
+ extras['hints']['union'] = True
c_data_type = lltype.Struct(struct_ctype.__name__, *llfields, **extras)
super(StructRepr, self).__init__(rtyper, s_struct, c_data_type)
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rstruct.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rstruct.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rstruct.py Fri Aug 11 12:54:43 2006
@@ -13,12 +13,17 @@
from pypy.rpython.test.test_llinterp import interpret
from ctypes import c_int, c_short, Structure, POINTER, pointer, c_char_p
-from ctypes import c_char, SetPointerType
+from ctypes import c_char, SetPointerType, Union, c_long
class tagpoint(Structure):
_fields_ = [("x", c_int),
("y", c_int)]
+class uvalue(Union):
+ _fields_ = [("c", c_char),
+ ("s", c_short),
+ ("l", c_long)]
+
def maketest():
class S1(Structure): _fields_ = [('x', c_int)]
class S2(Structure): _fields_ = [('x', POINTER(c_int))]
@@ -93,6 +98,17 @@
a.translator.view()
assert s.knowntype == int
+ def test_annotate_union(self):
+ def func(n):
+ u = uvalue(s=n)
+ return u.c
+ t = TranslationContext()
+ a = t.buildannotator()
+ s = a.build_types(func, [int])
+ if conftest.option.view:
+ a.translator.view()
+ assert s.knowntype == str
+
class Test_specialization:
def test_specialize_struct(self):
def create_struct():
@@ -250,3 +266,12 @@
func, expected = maketest()
fn = compile(func, [])
assert fn() == expected
+
+ def test_compile_union(self):
+ def func(n):
+ u = uvalue(s=n)
+ return u.c
+ fn = compile(func, [int])
+ res = fn(0x4567)
+ expected = func(0x4567)
+ assert res == expected
Modified: pypy/dist/pypy/translator/backendopt/malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/malloc.py (original)
+++ pypy/dist/pypy/translator/backendopt/malloc.py Fri Aug 11 12:54:43 2006
@@ -34,11 +34,22 @@
return False
FIELDTYPE = S._flds[fieldname]
if isinstance(FIELDTYPE, lltype.GcStruct):
+ if FIELDTYPE._hints.get('union'):
+ return False
return True
if len(S._names) == 1:
return True
return False
+def union_wrapper(S):
+ # check if 'S' is a GcStruct containing a single inlined *union* Struct
+ if not isinstance(S, lltype.GcStruct):
+ return False
+ assert not S._hints.get('union') # not supported: "GcUnion"
+ return (len(S._names) == 1 and
+ isinstance(S._flds[S._names[0]], lltype.Struct) and
+ S._flds[S._names[0]]._hints.get('union'))
+
def compute_lifetimes(graph):
"""Compute the static data flow of the graph: returns a list of LifeTime
@@ -183,6 +194,10 @@
except (ValueError, AttributeError), e:
pass
+ # must not remove unions inlined as the only field of a GcStruct
+ if union_wrapper(STRUCT):
+ return False
+
# success: replace each variable with a family of variables (one per field)
# 'flatnames' is a list of (STRUCTTYPE, fieldname_in_that_struct) that
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 Fri Aug 11 12:54:43 2006
@@ -1,5 +1,6 @@
import py
from pypy.translator.backendopt.malloc import remove_mallocs_once
+from pypy.translator.backendopt.malloc import union_wrapper
from pypy.translator.backendopt.inline import inline_function
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
@@ -9,6 +10,7 @@
from pypy.rpython.lltypesystem import lltype
from pypy.conftest import option
+
def check_malloc_removed(graph):
checkgraph(graph)
count1 = count2 = 0
@@ -16,7 +18,9 @@
if isinstance(node, Block):
for op in node.operations:
if op.opname == 'malloc':
- count1 += 1
+ S = op.args[0].value
+ if not union_wrapper(S): # union wrappers are fine
+ count1 += 1
if op.opname in ('direct_call', 'indirect_call'):
count2 += 1
assert count1 == 0 # number of mallocs left
@@ -36,9 +40,10 @@
simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks()))
if progress and option.view:
t.view()
- interp = LLInterpreter(t.rtyper)
- res = interp.eval_graph(graph, args)
- assert res == expected_result
+ if expected_result is not Ellipsis:
+ interp = LLInterpreter(t.rtyper)
+ res = interp.eval_graph(graph, args)
+ assert res == expected_result
if not progress:
break
if must_be_removed:
@@ -263,3 +268,14 @@
x.z += 3
return x.z
check(fn, [], [], 12)
+
+def test_union():
+ UNION = lltype.Struct('UNION', ('a', lltype.Signed), ('b', lltype.Signed),
+ hints = {'union': True})
+ BIG = lltype.GcStruct('BIG', ('u1', UNION), ('u2', UNION))
+ def fn():
+ x = lltype.malloc(BIG)
+ x.u1.a = 3
+ x.u2.b = 6
+ return x.u1.b * x.u2.a
+ check(fn, [], [], Ellipsis)
Modified: pypy/dist/pypy/translator/c/genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/genc.py (original)
+++ pypy/dist/pypy/translator/c/genc.py Fri Aug 11 12:54:43 2006
@@ -396,7 +396,7 @@
print >> fi, '/*** Structure definitions ***/'
print >> fi
for node in structdeflist:
- print >> fi, 'struct %s;' % node.name
+ print >> fi, '%s %s;' % (node.typetag, node.name)
print >> fi
for node in structdeflist:
for line in node.definition():
@@ -513,7 +513,7 @@
print >> f
for node in structdeflist:
if node.name:
- print >> f, 'struct %s;' % node.name
+ print >> f, '%s %s;' % (node.typetag, node.name)
print >> f
for node in structdeflist:
for line in node.definition():
Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py (original)
+++ pypy/dist/pypy/translator/c/node.py Fri Aug 11 12:54:43 2006
@@ -35,6 +35,7 @@
class StructDefNode:
+ typetag = 'struct'
def __init__(self, db, STRUCT, varlength=1):
self.db = db
@@ -48,6 +49,9 @@
basename = db.gettypedefnode(STRUCT).barename
basename = '%s_len%d' % (basename, varlength)
with_number = False
+ if STRUCT._hints.get('union'):
+ self.typetag = 'union'
+ assert STRUCT._gckind == 'raw' # not supported: "GcUnion"
if STRUCT._hints.get('c_name'):
self.barename = self.name = STRUCT._hints['c_name']
self.c_struct_field_name = self.verbatim_field_name
@@ -97,7 +101,7 @@
gcinfo = defaultproperty(computegcinfo)
def gettype(self):
- return 'struct %s @' % self.name
+ return '%s %s @' % (self.typetag, self.name)
def c_struct_field_name(self, name):
# occasionally overridden in __init__():
@@ -141,7 +145,7 @@
def definition(self):
if self.fields is None: # external definition only
return
- yield 'struct %s {' % self.name
+ yield '%s %s {' % (self.typetag, self.name)
is_empty = True
for name, typename in self.fields:
line = '%s;' % cdecl(typename, name)
@@ -151,7 +155,7 @@
is_empty = False
yield '\t' + line
if is_empty:
- yield '\t' + 'int _dummy; /* this struct is empty */'
+ yield '\t' + 'char _dummy; /* this struct is empty */'
yield '};'
for line in self.db.gcpolicy.struct_after_definition(self):
yield line
@@ -178,10 +182,12 @@
except ValueError:
yield '-1'
else:
- yield 'offsetof(struct %s, %s)' % (self.name, cname)
+ yield 'offsetof(%s %s, %s)' % (self.typetag,
+ self.name, cname)
class ArrayDefNode:
+ typetag = 'struct'
def __init__(self, db, ARRAY, varlength=1):
self.db = db
Modified: pypy/dist/pypy/translator/c/test/test_lltyped.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_lltyped.py (original)
+++ pypy/dist/pypy/translator/c/test/test_lltyped.py Fri Aug 11 12:54:43 2006
@@ -238,3 +238,16 @@
fn = self.getcompiled(llf)
res = fn()
assert res == 27
+
+ def test_union(self):
+ U = Struct('U', ('s', Signed), ('c', Char),
+ hints={'union': True})
+ u = malloc(U, immortal=True)
+ def llf(c=int):
+ u.s = 0x1020
+ u.c = chr(c)
+ return u.s
+
+ fn = self.getcompiled(llf)
+ res = fn(0x33)
+ assert res in [0x1033, 0x3320]
More information about the Pypy-commit
mailing list