From c9902ab8cf2ea34df7255faae303345b84684e30 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 22 Jul 2012 15:14:52 -0700 Subject: [PATCH] Add opaque StructType; Remove test/typehandle.py; Add test/opaque.py to demonstrate recursive type. --- llvm/_core.c | 4 +++ llvm/core.py | 60 +++++++++++++++++++++++++++++------- llvm/extra.cpp | 5 +++ llvm/extra.h | 5 +++ test/opaque.py | 40 ++++++++++++++++++++++++ test/test.py | 19 ++++++++++++ test/testattrs.py | 23 +++++++------- test/typehandle.py | 19 ------------ test/uses.py | 76 +++++++++++++++++++++++----------------------- 9 files changed, 171 insertions(+), 80 deletions(-) create mode 100755 test/opaque.py delete mode 100755 test/typehandle.py diff --git a/llvm/_core.c b/llvm/_core.c index 63b6ad5..269d57f 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -313,6 +313,8 @@ _wLLVMGetStructElementTypes(PyObject *self, PyObject *args) _wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int) +_wrap_obj2obj(LLVMIsOpaqueStruct, LLVMTypeRef, int) +_wrap_obj2obj(LLVMIsLiteralStruct, LLVMTypeRef, int) /*===-- Array types ------------------------------------------------------===*/ @@ -1379,6 +1381,8 @@ static PyMethodDef core_methods[] = { _method( LLVMCountStructElementTypes ) _method( LLVMGetStructElementTypes ) _method( LLVMIsPackedStruct ) + _method( LLVMIsOpaqueStruct ) + _method( LLVMIsLiteralStruct ) _method( LLVMGetStructName ) _method( LLVMSetStructName ) diff --git a/llvm/core.py b/llvm/core.py index 9cc6409..c3a77cc 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -507,13 +507,13 @@ class Module(llvm.Ownable, llvm.Cacheable): def add_library(self, name): return _core.LLVMModuleAddLibrary(self.ptr, name) - + def _get_id(self): return _core.LLVMGetModuleIdentifier(self.ptr) - + def _set_id(self, string): _core.LLVMSetModuleIdentifier(self.ptr, string) - + id = property(_get_id, _set_id) #===----------------------------------------------------------------------=== @@ -584,6 +584,15 @@ class Type(object): return _make_type(_core.LLVMFunctionType(return_ty.ptr, params, var_arg), TYPE_FUNCTION) + @staticmethod + def opaque(name): + """Create a opaque StructType""" + if not name: + raise llvm.LLVMException("Must specify a name") + + objptr = _core.LLVMStructTypeIdentified(name) + return _make_type(objptr, TYPE_STRUCT) + @staticmethod def struct(element_tys, name=''): # not packed """Create a (unpacked) structure type. @@ -591,17 +600,17 @@ class Type(object): Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a unpacked structure. For a packed one, use the packed_struct() method. - - If name is not '', creates a identified type; + + If name is not '', creates a identified type; otherwise, creates a literal type.""" elems = unpack_types(element_tys) - + if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) _core.LLVMSetStructBody(objptr, elems, 0) else: # create Literal StructType objptr = _core.LLVMStructType(elems, 0) - + return _make_type(objptr, TYPE_STRUCT) @staticmethod @@ -611,11 +620,11 @@ class Type(object): Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a packed structure. For an unpacked one, use the struct() method. - - If name is not '', creates a identified type; + + If name is not '', creates a identified type; otherwise, creates a literal type.""" elems = unpack_types(element_tys) - + if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) _core.LLVMSetStructBody(objptr, elems, 0) @@ -750,6 +759,23 @@ class StructType(Type): pp = _core.LLVMGetStructElementTypes(self.ptr) return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] + def set_body(self, elems, packed=False): + """Filled the body of a opaque type. + """ + # check + if not self.is_opaque: + raise llvm.LLVMException("Body is already defined.") + + # prepare arguments + elems = unpack_types(elems) + if packed: + packed = 1 + else: + packed = 0 + + # call c API + _core.LLVMSetStructBody(self.ptr, elems, packed) + @property def packed(self): """True if the structure is packed, False otherwise.""" @@ -757,12 +783,24 @@ class StructType(Type): def _set_name(self, name): _core.LLVMSetStructName(self.ptr, name) - + def _get_name(self): return _core.LLVMGetStructName(self.ptr) name = property(_get_name, _set_name) + @property + def is_literal(self): + return bool(_core.LLVMIsLiteralStruct(self.ptr)) + + @property + def is_identified(self): + return not _core.LLVMIsLiteralStruct(self.ptr) + + @property + def is_opaque(self): + return bool(_core.LLVMIsOpaqueStruct(self.ptr)) + class ArrayType(Type): """Represents an array type.""" diff --git a/llvm/extra.cpp b/llvm/extra.cpp index d4030af..60b7ef9 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -90,6 +90,11 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +int LLVMIsLiteralStruct(LLVMTypeRef type) +{ + return llvm::unwrap(type)->isLiteral(); +} + LLVMTypeRef LLVMStructTypeIdentified(const char * name) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index c3772aa..ed52a10 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -41,6 +41,11 @@ extern "C" { #endif +/* + * Wraps StructType::isLiteral() + */ +int LLVMIsLiteralStruct(LLVMTypeRef type); + /* * Wraps StructType::create() */ diff --git a/test/opaque.py b/test/opaque.py new file mode 100755 index 0000000..329a673 --- /dev/null +++ b/test/opaque.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +from llvm.core import * +from llvm import LLVMException + +import logging, unittest + +class TestOpaque(unittest.TestCase): + def test_opaque(self): + # Create an opaque type + ts = Type.opaque('mystruct') + self.assertIn('type opaque', str(ts)) + self.assertTrue(ts.is_opaque) + self.assertTrue(ts.is_identified) + self.assertFalse(ts.is_literal) + + logging.debug(ts) + + # Create a recursive type + ts.set_body([Type.int(), Type.pointer(ts)]) + + self.assertEqual(ts.elements[0], Type.int()) + self.assertEqual(ts.elements[1], Type.pointer(ts)) + self.assertEqual(ts.elements[1].pointee, ts) + self.assertFalse(ts.is_opaque) # is not longer a opaque type + + logging.debug(ts) + + with self.assertRaises(LLVMException): + # Cannot redefine + ts.set_body([]) + + def test_opaque_with_no_name(self): + with self.assertRaises(LLVMException): + Type.opaque('') + +if __name__ == '__main__': + unittest.main() + + diff --git a/test/test.py b/test/test.py index 10fe019..bbc43f4 100755 --- a/test/test.py +++ b/test/test.py @@ -67,6 +67,25 @@ class TestModule(unittest.TestCase): for elty in struct.elements: self.assertEqual(elty, Type.int()) + # rename identified type + struct.name = 'new_name' + self.assertEqual(struct.name, 'new_name') + self.assertIs(m.get_type_named("struct.two.int"), None) + + self.assertEqual(got_struct.name, struct.name) + + # remove identified type + struct.name = '' + + self.assertIs(m.get_type_named("struct.two.int"), None) + self.assertIs(m.get_type_named("new_name"), None) + + # another name + + struct.name = 'another.name' + self.assertEqual(struct.name, 'another.name') + self.assertEqual(got_struct.name, struct.name) + def testglobal_variable(self): """Global variables.""" m = Module.new("test5.1") diff --git a/test/testattrs.py b/test/testattrs.py index 10381fb..24a7b46 100755 --- a/test/testattrs.py +++ b/test/testattrs.py @@ -3,9 +3,10 @@ from llvm.core import * from io import StringIO +import unittest def make_module(): - test_module = """ + test_module = u""" define i32 @sum(i32, i32) { entry: %2 = add i32 %0, %1 @@ -14,15 +15,13 @@ def make_module(): """ return Module.from_assembly(StringIO(test_module)) +class TestAttr(unittest.TestCase): + def test_align(self): + m = make_module() + f = m.get_function_named('sum') + f.args[0].alignment = 16 + self.assertIn("align 16", str(f)) + self.assertEqual(f.args[0].alignment, 16) -def test_align(m): - f = m.get_function_named('sum') - f.args[0].alignment = 16 - assert "align 16" in str(f) - assert f.args[0].alignment == 16 - - -m = make_module() -test_align(m) - - +if __name__ == '__main__': + unittest.main() diff --git a/test/typehandle.py b/test/typehandle.py deleted file mode 100755 index 4adb53d..0000000 --- a/test/typehandle.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python - -from llvm.core import * - -# create a type handle object -th = TypeHandle.new(Type.opaque()) - -# create the struct with an opaque* instead of self* -ts = Type.struct([ Type.int(), Type.pointer(th.type) ]) - -# unify the types -th.type.refine(ts) - -# create a module, and add a "typedef" -m = Module.new('mod1') -m.add_type_name("struct.node", th.type) - -# show what we created -print(m) diff --git a/test/uses.py b/test/uses.py index d0c7e21..97040fa 100755 --- a/test/uses.py +++ b/test/uses.py @@ -2,44 +2,44 @@ from llvm.core import * -m = Module.new('a') -t = Type.int() -ft = Type.function(t, [t, t, t]) -f = m.add_function(ft, "func") -b = f.append_basic_block('entry') -bld = Builder.new(b) -tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") -tmp2 = bld.add(tmp1, f.args[1], "tmp2") -tmp3 = bld.add(tmp1, f.args[2], "tmp3") -bld.ret(tmp3) +import unittest, logging -print("-"*60) -print(m) -print("-"*60) +class TestUses(unittest.TestCase): + def test_uses(self): + m = Module.new('a') + t = Type.int() + ft = Type.function(t, [t, t, t]) + f = m.add_function(ft, "func") + b = f.append_basic_block('entry') + bld = Builder.new(b) + tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") + tmp2 = bld.add(tmp1, f.args[1], "tmp2") + tmp3 = bld.add(tmp1, f.args[2], "tmp3") + bld.ret(tmp3) -print("Testing use count ..", end=' ') -c1 = f.args[0].use_count == 1 -c2 = f.args[1].use_count == 1 -c3 = f.args[2].use_count == 1 -c4 = tmp1.use_count == 2 -c5 = tmp2.use_count == 0 -c6 = tmp3.use_count == 1 -if c1 and c2 and c3 and c4 and c5 and c6: - print("OK") -else: - print("FAIL") + logging.debug("-"*60) + logging.debug(m) + logging.debug("-"*60) + + logging.debug("Testing use count ..", end=' ') + self.assertEqual(f.args[0].use_count, 1) + self.assertEqual(f.args[1].use_count, 1) + self.assertEqual(f.args[2].use_count, 1) + self.assertEqual(tmp1.use_count, 2) + self.assertEqual(tmp2.use_count, 0) + self.assertEqual(tmp3.use_count, 1) + + logging.debug("Testing uses ..", end=' ') + self.assertIs(f.args[0].uses[0], tmp1) + self.assertEqual(len(f.args[0].uses), 1) + self.assertIs(f.args[1].uses[0], tmp2) + self.assertEqual(len(f.args[1].uses), 1) + self.assertIs(f.args[2].uses[0], tmp3) + self.assertEqual(len(f.args[2].uses), 1) + self.assertEqual(len(tmp1.uses), 2) + self.assertEqual(len(tmp2.uses), 0) + self.assertEqual(len(tmp3.uses), 1) + +if __name__ == '__main__': + unittest.main() -print("Testing uses ..", end=' ') -c1 = f.args[0].uses[0] is tmp1 -c2 = len(f.args[0].uses) == 1 -c3 = f.args[1].uses[0] is tmp2 -c4 = len(f.args[1].uses) == 1 -c5 = f.args[2].uses[0] is tmp3 -c6 = len(f.args[2].uses) == 1 -c7 = len(tmp1.uses) == 2 -c8 = len(tmp2.uses) == 0 -c9 = len(tmp3.uses) == 1 -if c1 and c2 and c3 and c4 and c5 and c6 and c7 and c8 and c9: - print("OK") -else: - print("FAIL")