[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