Add opaque StructType;
Remove test/typehandle.py; Add test/opaque.py to demonstrate recursive type.
This commit is contained in:
parent
b71d22b570
commit
c9902ab8cf
9 changed files with 171 additions and 80 deletions
|
|
@ -313,6 +313,8 @@ _wLLVMGetStructElementTypes(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
|
|
||||||
_wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int)
|
_wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int)
|
||||||
|
_wrap_obj2obj(LLVMIsOpaqueStruct, LLVMTypeRef, int)
|
||||||
|
_wrap_obj2obj(LLVMIsLiteralStruct, LLVMTypeRef, int)
|
||||||
|
|
||||||
/*===-- Array types ------------------------------------------------------===*/
|
/*===-- Array types ------------------------------------------------------===*/
|
||||||
|
|
||||||
|
|
@ -1379,6 +1381,8 @@ static PyMethodDef core_methods[] = {
|
||||||
_method( LLVMCountStructElementTypes )
|
_method( LLVMCountStructElementTypes )
|
||||||
_method( LLVMGetStructElementTypes )
|
_method( LLVMGetStructElementTypes )
|
||||||
_method( LLVMIsPackedStruct )
|
_method( LLVMIsPackedStruct )
|
||||||
|
_method( LLVMIsOpaqueStruct )
|
||||||
|
_method( LLVMIsLiteralStruct )
|
||||||
_method( LLVMGetStructName )
|
_method( LLVMGetStructName )
|
||||||
_method( LLVMSetStructName )
|
_method( LLVMSetStructName )
|
||||||
|
|
||||||
|
|
|
||||||
38
llvm/core.py
38
llvm/core.py
|
|
@ -584,6 +584,15 @@ class Type(object):
|
||||||
return _make_type(_core.LLVMFunctionType(return_ty.ptr, params,
|
return _make_type(_core.LLVMFunctionType(return_ty.ptr, params,
|
||||||
var_arg), TYPE_FUNCTION)
|
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
|
@staticmethod
|
||||||
def struct(element_tys, name=''): # not packed
|
def struct(element_tys, name=''): # not packed
|
||||||
"""Create a (unpacked) structure type.
|
"""Create a (unpacked) structure type.
|
||||||
|
|
@ -750,6 +759,23 @@ class StructType(Type):
|
||||||
pp = _core.LLVMGetStructElementTypes(self.ptr)
|
pp = _core.LLVMGetStructElementTypes(self.ptr)
|
||||||
return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ]
|
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
|
@property
|
||||||
def packed(self):
|
def packed(self):
|
||||||
"""True if the structure is packed, False otherwise."""
|
"""True if the structure is packed, False otherwise."""
|
||||||
|
|
@ -763,6 +789,18 @@ class StructType(Type):
|
||||||
|
|
||||||
name = property(_get_name, _set_name)
|
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):
|
class ArrayType(Type):
|
||||||
"""Represents an array type."""
|
"""Represents an array type."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,11 @@ char *do_print(W obj)
|
||||||
return strdup(buf.str().c_str());
|
return strdup(buf.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LLVMIsLiteralStruct(LLVMTypeRef type)
|
||||||
|
{
|
||||||
|
return llvm::unwrap<llvm::StructType>(type)->isLiteral();
|
||||||
|
}
|
||||||
|
|
||||||
LLVMTypeRef LLVMStructTypeIdentified(const char * name)
|
LLVMTypeRef LLVMStructTypeIdentified(const char * name)
|
||||||
{
|
{
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps StructType::isLiteral()
|
||||||
|
*/
|
||||||
|
int LLVMIsLiteralStruct(LLVMTypeRef type);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wraps StructType::create()
|
* Wraps StructType::create()
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
40
test/opaque.py
Executable file
40
test/opaque.py
Executable file
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
19
test/test.py
19
test/test.py
|
|
@ -67,6 +67,25 @@ class TestModule(unittest.TestCase):
|
||||||
for elty in struct.elements:
|
for elty in struct.elements:
|
||||||
self.assertEqual(elty, Type.int())
|
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):
|
def testglobal_variable(self):
|
||||||
"""Global variables."""
|
"""Global variables."""
|
||||||
m = Module.new("test5.1")
|
m = Module.new("test5.1")
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
from llvm.core import *
|
from llvm.core import *
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
def make_module():
|
def make_module():
|
||||||
test_module = """
|
test_module = u"""
|
||||||
define i32 @sum(i32, i32) {
|
define i32 @sum(i32, i32) {
|
||||||
entry:
|
entry:
|
||||||
%2 = add i32 %0, %1
|
%2 = add i32 %0, %1
|
||||||
|
|
@ -14,15 +15,13 @@ def make_module():
|
||||||
"""
|
"""
|
||||||
return Module.from_assembly(StringIO(test_module))
|
return Module.from_assembly(StringIO(test_module))
|
||||||
|
|
||||||
|
class TestAttr(unittest.TestCase):
|
||||||
def test_align(m):
|
def test_align(self):
|
||||||
|
m = make_module()
|
||||||
f = m.get_function_named('sum')
|
f = m.get_function_named('sum')
|
||||||
f.args[0].alignment = 16
|
f.args[0].alignment = 16
|
||||||
assert "align 16" in str(f)
|
self.assertIn("align 16", str(f))
|
||||||
assert f.args[0].alignment == 16
|
self.assertEqual(f.args[0].alignment, 16)
|
||||||
|
|
||||||
|
|
||||||
m = make_module()
|
|
||||||
test_align(m)
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
76
test/uses.py
76
test/uses.py
|
|
@ -2,44 +2,44 @@
|
||||||
|
|
||||||
from llvm.core import *
|
from llvm.core import *
|
||||||
|
|
||||||
m = Module.new('a')
|
import unittest, logging
|
||||||
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("-"*60)
|
class TestUses(unittest.TestCase):
|
||||||
print(m)
|
def test_uses(self):
|
||||||
print("-"*60)
|
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=' ')
|
logging.debug("-"*60)
|
||||||
c1 = f.args[0].use_count == 1
|
logging.debug(m)
|
||||||
c2 = f.args[1].use_count == 1
|
logging.debug("-"*60)
|
||||||
c3 = f.args[2].use_count == 1
|
|
||||||
c4 = tmp1.use_count == 2
|
logging.debug("Testing use count ..", end=' ')
|
||||||
c5 = tmp2.use_count == 0
|
self.assertEqual(f.args[0].use_count, 1)
|
||||||
c6 = tmp3.use_count == 1
|
self.assertEqual(f.args[1].use_count, 1)
|
||||||
if c1 and c2 and c3 and c4 and c5 and c6:
|
self.assertEqual(f.args[2].use_count, 1)
|
||||||
print("OK")
|
self.assertEqual(tmp1.use_count, 2)
|
||||||
else:
|
self.assertEqual(tmp2.use_count, 0)
|
||||||
print("FAIL")
|
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")
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue