diff --git a/CHANGELOG b/CHANGELOG index 45d6a5f..12bb294 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,35 +1,5 @@ -2014-04-28 0.12.5: ---------------------- - * Fixes memory leaks (#92) - * Fixes tarball (#99) - -2014-03-20 0.12.4: ---------------------- - * Add dylib_import_library and friends - * Fix BasicBlock downcast - * Module hashing - * Fix test script - -2014-02-18 0.12.3: ---------------------- - * Fix deprecation message for py2.6 - * Fix llvm_cbuilder for using deprecated_alloca - * Merged PR #88 by cantora - * Merged PR #94 by cgohlke - -2014-02-04 0.12.2: ---------------------- - * enhance wrapper efficiency by moving some capsule code into C++ - * fix unclosed file handler in avx_support - * multiple-dimension insert_value, extract_value - * various minor fixes - -2013-11-11 0.12.1: ---------------------- - * various bug fixes - -2013-08-28 0.12.0: ---------------------- +2013-8-28 0.12.0: +-------------------- * update to LLVM 3.3 and maintain compatibility with LLVM 3.2 * add LLRT for minimal support for 64-bit divmod on 32-bit platform * start to adopt MCJIT (not quite usable on win32) diff --git a/MANIFEST.in b/MANIFEST.in index 25a211d..295794c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ -include CHANGELOG LICENSE README.rst setup.py MANIFEST.in versioneer.py +include CHANGELOG LICENSE README setup.py MANIFEST.in recursive-include llvm * -recursive-include llvmpy * recursive-include www * recursive-include test * recursive-include tools * diff --git a/README.rst b/README.rst index a1abf84..0fbcd24 100644 --- a/README.rst +++ b/README.rst @@ -30,13 +30,10 @@ Quickstart to separate your custom build from the default system package. Please replace ``LLVM_INSTALL_PATH`` with your own path. -3. Run ``REQUIRES_RTTI=1 make install`` to build and install. +3. Run ``REQUIRES_RTTI=1 make`` to build. **Note**: With LLVM 3.2, the default build configuration has C++ RTTI disabled. However, llvmpy requires RTTI. - - **Note**: Use ``make -j2 install`` to enable concurrent build. - Replace ``2`` with the actual number of processor you have. 4. Get llvm-py and install it:: diff --git a/buildscripts/condarecipe/run_test.py b/buildscripts/condarecipe/run_test.py index 682b8d4..281a599 100644 --- a/buildscripts/condarecipe/run_test.py +++ b/buildscripts/condarecipe/run_test.py @@ -4,8 +4,6 @@ import llvm from llvm.core import Module from llvm.ee import EngineBuilder -from llvm.utils import check_intrinsics - m = Module.new('fjoidajfa') eb = EngineBuilder.new(m) target = eb.select_target() @@ -15,8 +13,7 @@ if sys.platform == 'darwin': s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] assert target.triple.startswith(s + '-apple-darwin') -assert llvm.test(verbosity=2, run_isolated=False) == 0 -#check_intrinsics.main() +assert llvm.test(verbosity=2) == 0 print('llvm.__version__: %s' % llvm.__version__) #assert llvm.__version__ == '0.12.0' diff --git a/buildscripts/condarecipe_devel/bld.bat b/buildscripts/condarecipe_devel/bld.bat new file mode 100644 index 0000000..e9177c5 --- /dev/null +++ b/buildscripts/condarecipe_devel/bld.bat @@ -0,0 +1,6 @@ +set LLVMPY_DYNLINK=0 +set INCLUDE=%LIBRARY_INC% +set LIBPATH=%LIBRARY_LIB% +set LIB=%LIBRARY_LIB% +%PYTHON% setup.py install +if errorlevel 1 exit 1 diff --git a/buildscripts/condarecipe_devel/build.sh b/buildscripts/condarecipe_devel/build.sh new file mode 100644 index 0000000..5c98fde --- /dev/null +++ b/buildscripts/condarecipe_devel/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ (`uname` == Linux) && (`uname -m` != armv6l) ]] +then + export CC=gcc + #gcc44 + export CXX=g++ + #g++44 +fi + +export LLVMPY_DYNLINK=$DISTRO_BUILD + +$PYTHON setup.py install diff --git a/buildscripts/condarecipe_devel/meta.yaml b/buildscripts/condarecipe_devel/meta.yaml new file mode 100644 index 0000000..4f7162b --- /dev/null +++ b/buildscripts/condarecipe_devel/meta.yaml @@ -0,0 +1,28 @@ +package: + name: llvmpy + version: 99.9.9 + +source: + git_url: git@github.com:llvmpy/llvmpy.git + git_tag: devel + +requirements: + build: + - llvm + - python + #- chrpath [linux] + run: + - llvm [unix] + - python + +test: + imports: + - llvm + - llvmpy + - llvmpy._api + - llvmpy._capsule + - llpython + - llvm_array + - llvm_cbuilder + + diff --git a/buildscripts/condarecipe_devel/run_test.py b/buildscripts/condarecipe_devel/run_test.py new file mode 100644 index 0000000..281a599 --- /dev/null +++ b/buildscripts/condarecipe_devel/run_test.py @@ -0,0 +1,19 @@ +import sys +import platform +import llvm + +from llvm.core import Module +from llvm.ee import EngineBuilder +m = Module.new('fjoidajfa') +eb = EngineBuilder.new(m) +target = eb.select_target() + +print('target.triple=%r' % target.triple) +if sys.platform == 'darwin': + s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] + assert target.triple.startswith(s + '-apple-darwin') + +assert llvm.test(verbosity=2) == 0 + +print('llvm.__version__: %s' % llvm.__version__) +#assert llvm.__version__ == '0.12.0' diff --git a/docs/source/index.rst b/docs/source/index.rst index fbf5c8b..7798b77 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -llvmpy -====== +Documentation for llvmpy +======================== Contents: @@ -22,7 +22,7 @@ Contents: Indices and tables ------------------- +================== * :ref:`genindex` * :ref:`modindex` diff --git a/example/vector_instr.py b/example/vector_instr.py deleted file mode 100644 index e49d06a..0000000 --- a/example/vector_instr.py +++ /dev/null @@ -1,152 +0,0 @@ -''' -This example shows: -1) how to use vector instructions -2) how to take advantage of LLVM loop vectorization to transform scalar - operations to vector operations -''' - -from __future__ import print_function -import llvm.core as lc -import llvm.ee as le -import llvm.passes as lp -from ctypes import CFUNCTYPE, POINTER, c_int, c_float - -def build_manual_vector(): - mod = lc.Module.new('manual.vector') - intty = lc.Type.int(32) - vecty = lc.Type.vector(lc.Type.float(), 4) - aryty = lc.Type.pointer(lc.Type.float()) - fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty]) - fn = mod.add_function(fnty, name='vector_add') - bbentry = fn.append_basic_block('entry') - bbloopcond = fn.append_basic_block('loop.cond') - bbloopbody = fn.append_basic_block('loop.body') - bbexit = fn.append_basic_block('exit') - builder = lc.Builder.new(bbentry) - - # populate function body - in1, in2, out, size = fn.args - ZERO = lc.Constant.null(intty) - loopi_ptr = builder.alloca(intty) - builder.store(ZERO, loopi_ptr) - - builder.branch(bbloopcond) - builder.position_at_end(bbloopcond) - - loopi = builder.load(loopi_ptr) - loopcond = builder.icmp(lc.ICMP_ULT, loopi, size) - - builder.cbranch(loopcond, bbloopbody, bbexit) - builder.position_at_end(bbloopbody) - - vecaryty = lc.Type.pointer(vecty) - in1asvec = builder.bitcast(builder.gep(in1, [loopi]), vecaryty) - in2asvec = builder.bitcast(builder.gep(in2, [loopi]), vecaryty) - outasvec = builder.bitcast(builder.gep(out, [loopi]), vecaryty) - - vec1 = builder.load(in1asvec) - vec2 = builder.load(in2asvec) - - vecout = builder.fadd(vec1, vec2) - - builder.store(vecout, outasvec) - - next = builder.add(loopi, lc.Constant.int(intty, 4)) - builder.store(next, loopi_ptr) - - builder.branch(bbloopcond) - builder.position_at_end(bbexit) - - builder.ret_void() - - return mod, fn - - -def build_auto_vector(): - mod = lc.Module.new('auto.vector') - # Loop vectorize is sensitive to the size of the index size(!?) - intty = lc.Type.int(tuple.__itemsize__ * 8) - aryty = lc.Type.pointer(lc.Type.float()) - fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty]) - fn = mod.add_function(fnty, name='vector_add') - bbentry = fn.append_basic_block('entry') - bbloopcond = fn.append_basic_block('loop.cond') - bbloopbody = fn.append_basic_block('loop.body') - bbexit = fn.append_basic_block('exit') - builder = lc.Builder.new(bbentry) - - # populate function body - in1, in2, out, size = fn.args - in1.add_attribute(lc.ATTR_NO_ALIAS) - in2.add_attribute(lc.ATTR_NO_ALIAS) - out.add_attribute(lc.ATTR_NO_ALIAS) - ZERO = lc.Constant.null(intty) - loopi_ptr = builder.alloca(intty) - builder.store(ZERO, loopi_ptr) - - builder.branch(bbloopcond) - builder.position_at_end(bbloopcond) - - loopi = builder.load(loopi_ptr) - loopcond = builder.icmp(lc.ICMP_ULT, loopi, size) - - builder.cbranch(loopcond, bbloopbody, bbexit) - builder.position_at_end(bbloopbody) - - in1elem = builder.load(builder.gep(in1, [loopi])) - in2elem = builder.load(builder.gep(in2, [loopi])) - - outelem = builder.fadd(in1elem, in2elem) - - builder.store(outelem, builder.gep(out, [loopi])) - - next = builder.add(loopi, lc.Constant.int(intty, 1)) - builder.store(next, loopi_ptr) - - builder.branch(bbloopcond) - builder.position_at_end(bbexit) - - builder.ret_void() - - return mod, fn - -def example(title, module_builder, opt): - print(title.center(80, '=')) - mod, fn = module_builder() - - eb = le.EngineBuilder.new(mod).opt(3) - if opt: - print('opt') - tm = eb.select_target() - pms = lp.build_pass_managers(mod=mod, tm=tm, opt=3, loop_vectorize=True, - fpm=False) - pms.pm.run(mod) - - print(mod) - print(mod.to_native_assembly()) - - engine = eb.create() - ptr = engine.get_pointer_to_function(fn) - - callable = CFUNCTYPE(None, POINTER(c_float), POINTER(c_float), - POINTER(c_float), c_int)(ptr) - - N = 20 - in1 = (c_float * N)(*range(N)) - in2 = (c_float * N)(*range(N)) - out = (c_float * N)() - - print('in1: ', list(in1)) - print('in1: ', list(in2)) - - callable(in1, in2, out, N) - - print('out', list(out)) - - -def main(): - example('manual vector function', build_manual_vector, False) - example('auto vector function', build_auto_vector, True) - -if __name__ == '__main__': - main() diff --git a/llvm/__init__.py b/llvm/__init__.py index 9b24112..dc9852f 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -9,8 +9,6 @@ version = extra.get_llvm_version() del extra class Wrapper(object): - __slots__ = '__ptr' - def __init__(self, ptr): assert ptr self.__ptr = ptr @@ -34,14 +32,14 @@ def _extract_ptrs(objs): class LLVMException(Exception): pass -def test(verbosity=3, run_isolated=True): +def test(verbosity=1): """test(verbosity=1) -> TextTestResult Run self-test, and return the number of failures + errors """ from llvm.tests import run - result = run(verbosity=verbosity, run_isolated=run_isolated) - errct = len(result.failures) + len(result.errors) + result = run(verbosity=verbosity) + + return len(result.failures) + len(result.errors) - return errct diff --git a/llvm/abi.py b/llvm/abi.py new file mode 100644 index 0000000..49f9271 --- /dev/null +++ b/llvm/abi.py @@ -0,0 +1,195 @@ +''' +Provide C ABI information + +Reference to +- http://clang.llvm.org/doxygen/classclang_1_1ABIArgInfo.html +- http://clang.llvm.org/doxygen/CodeGen_2TargetInfo_8cpp_source.html + See X86_32ABIInfo, computeInfo, classifyArgumentType +''' +from collections import namedtuple +import llvm.core as lc + +AGGREGATE_TYPES = frozenset([lc.TYPE_STRUCT, lc.TYPE_ARRAY]) + +class ABIArgInfo(object): + ''' + ABI argument info + + Try to be a close translation of clang::ABIArgInfo. + (See http://clang.llvm.org/doxygen/classclang_1_1ABIArgInfo.html) + But, this is for C not C++. + ''' + __slots__ = ['_kind', '_typedata', '_paddingtype', '_uintdata', + '_booldata0', '_booldata1', '_inreg', '_paddinginreg'] + + # Enum for argument info kind + DIRECT = 0 + EXTEND = 1 + IGNORE = 2 + INDIRECT = 3 + EXPAND = 4 + + def __init__(self, kind, td=None, ui=0, b0=False, b1=False, ir=False, + pir=False, p=None): + self._kind = kind + self._typedata = td + self._paddingtype = p + self._uintdata = ui + self._booldata0 = b0 + self._booldata1 = b1 + self._inreg = ir + self._paddinginreg = pir + + def __repr__(self): + data = [] + if self.is_direct: + data.append('Direct') + data.append('coerce=%s' % self.coerce_to_type) + elif self.is_indirect: + data.append('Indirect') + data.append('align=%s' % self.indirect_align) + data.append('byval=%s' % self.indirect_by_val) + data.append('realign=%s' % self.indirect_by_realign) + elif self.is_extend: + data.append('Extend') + elif self.is_ignore: + data.append('Ignore') + elif self.is_expand: + data.append('Expand') + else: + raise AssertionError('invalid kind: %s' % self._kind) + + return '' % ' '.join(data) + + # ---- accessors ---- + + @property + def is_direct(self): + return self._kind == self.DIRECT + + @property + def is_indirect(self): + return self._kind == self.INDIRECT + + @property + def is_extend(self): + return self._kind == self.EXTEND + + @property + def is_ignore(self): + return self._kind == self.IGNORE + + @property + def is_expand(self): + return self._kind == self.EXPAND + + @property + def can_have_coerce_to_type(self): + return self.is_direct or self.is_extend + + @property + def direct_offset(self): + assert self.is_direct or self.is_extend + return self._uintdata + + @property + def padding_type(self): + return self._paddingtype + + @property + def padding_in_reg(self): + return self._paddinginreg + + @property + def coerce_to_type(self): + assert self.can_have_coerce_to_type + return self._typedata + + @coerce_to_type.setter + def coerce_to_type(self, ty): + self._typedata = ty + + @property + def in_reg(self): + return self.is_direct() or self.is_extend or self.is_indirect + + @property + def indirect_align(self): + assert self.is_indirect + return self._uintdata + + @property + def indirect_by_val(self): + assert self.is_indirect + return self._booldata0 + + @property + def indirect_by_realign(self): + assert self.is_indirect + return self._booldata1 + + # ---- factories ---- + + @classmethod + def get_ignore(cls): + return cls(kind=cls.IGNORE) + + @classmethod + def get_extend(cls, ty=None): + return cls(kind=cls.EXTEND, td=ty) + + @classmethod + def get_direct(cls): + return cls(kind=cls.DIRECT) + +class ABIInfo(object): + def __init__(self, datalayout): + self.datalayout = datalayout + + def compute_info(self, return_type, args): + self.return_info = self.classify_return_type(return_type) + self.arg_infos = [] + for a in args: + info = self.classify_argument_type(a) + self.arg_infos.append(info) + + def classify_return_type(self, retty): + raise NotImplementedError + + def classify_argument_type(self, argty): + raise NotImplementedError + +class DefaultABIInfo(ABIInfo): + def classify_argument_type(self, argty): + if argty.kind in AGGREGATE_TYPES: + return ABIArgInfo.get_indirect() + + if self.promotable_integers(argty): + return ABIArgInfo.get_extend() + else: + return ABIArgInfo.get_direct() + + def classify_return_type(self, retty): + if retty.kind == lc.TYPE_VOID: + return ABIArgInfo.get_ignore() + + if retty.kind in AGGREGATE_TYPES: + return ABIArgInfo.get_indirect() + + if self.promotable_integers(retty): + return ABIArgInfo.get_extend() + else: + return ABIArgInfo.get_direct() + + def promotable_integers(self, ty): + if ty.kind != lc.TYPE_INTEGER: + return False + abisize = self.datalayout.abi_size(ty) * 8 + return ty.width < abisize + +#------------------------------------------------------------------------------ +# X86-32 +#------------------------------------------------------------------------------ + +class X86_32ABIInfo(ABIInfo): + MIN_ABI_STACK_ALIGN = 4 # bytes diff --git a/llvm/core.py b/llvm/core.py index 4db8135..8a4ac2d 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -41,7 +41,7 @@ import contextlib, weakref import llvm from llvm._intrinsic_ids import * -from llvm.deprecated import deprecated + from llvmpy import api #===----------------------------------------------------------------------=== @@ -379,7 +379,6 @@ class Module(llvm.Wrapper): module_obj = Module.new('my_module') """ - __slots__ = '__weakref__' __cache = weakref.WeakValueDictionary() def __new__(cls, ptr): @@ -452,12 +451,12 @@ class Module(llvm.Wrapper): """ return str(self._ptr) - def __hash__(self): - return id(self._ptr) - def __eq__(self, rhs): + assert isinstance(rhs, Module), type(rhs) if isinstance(rhs, Module): - return self._ptr == rhs._ptr + return str(self) == str(rhs) + else: + return False def __ne__(self, rhs): return not (self == rhs) @@ -689,7 +688,6 @@ class Type(llvm.Wrapper): Use one of the static methods to create an instance. Example: ty = Type.double() """ - __slots__ = '__name__' _type_ = api.llvm.Type def __init__(self, ptr): @@ -882,7 +880,6 @@ class Type(llvm.Wrapper): class IntegerType(Type): """Represents an integer type.""" - __slots__ = () _type_ = api.llvm.IntegerType @property @@ -892,7 +889,6 @@ class IntegerType(Type): class FunctionType(Type): """Represents a function type.""" - __slots__ = () _type_ = api.llvm.FunctionType @property @@ -922,7 +918,6 @@ class FunctionType(Type): class StructType(Type): """Represents a structure type.""" _type_ = api.llvm.StructType - __slots__ = () @property def element_count(self): @@ -981,7 +976,6 @@ class StructType(Type): class ArrayType(Type): """Represents an array type.""" _type_ = api.llvm.ArrayType - __slots__ = () @property def element(self): @@ -993,7 +987,6 @@ class ArrayType(Type): class PointerType(Type): _type_ = api.llvm.PointerType - __slots__ = () @property def pointee(self): @@ -1005,7 +998,6 @@ class PointerType(Type): class VectorType(Type): _type_ = api.llvm.VectorType - __slots__ = () @property def element(self): @@ -1017,7 +1009,6 @@ class VectorType(Type): class Value(llvm.Wrapper): _type_ = api.llvm.Value - __slots__ = '__weakref__' def __init__(self, builder, ptr): assert builder is _ValueFactory @@ -1086,7 +1077,6 @@ class Value(llvm.Wrapper): class User(Value): _type_ = api.llvm.User - __slots__ = () @property def operand_count(self): @@ -1101,7 +1091,6 @@ class User(Value): class Constant(User): _type_ = api.llvm.Constant - __slots__ = () @staticmethod def null(ty): @@ -1287,7 +1276,6 @@ class Constant(User): class ConstantExpr(Constant): _type_ = api.llvm.ConstantExpr - __slots__ = () @property def opcode(self): @@ -1298,20 +1286,19 @@ class ConstantExpr(Constant): return self._ptr.getOpcodeName() class ConstantAggregateZero(Constant): - __slots__ = () + pass class ConstantDataArray(Constant): - __slots__ = () + pass class ConstantDataVector(Constant): - __slots__ = () + pass class ConstantInt(Constant): _type_ = api.llvm.ConstantInt - __slots__ = () @property def z_ext_value(self): @@ -1327,32 +1314,30 @@ class ConstantInt(Constant): class ConstantFP(Constant): - __slots__ = () + pass class ConstantArray(Constant): - __slots__ = () + pass class ConstantStruct(Constant): - __slots__ = () + pass class ConstantVector(Constant): - __slots__ = () + pass class ConstantPointerNull(Constant): - __slots__ = () + pass class UndefValue(Constant): - __slots__ = () - + pass class GlobalValue(Constant): _type_ = api.llvm.GlobalValue - __slots__ = () def _get_linkage(self): return self._ptr.getLinkage() @@ -1398,7 +1383,6 @@ class GlobalValue(Constant): class GlobalVariable(GlobalValue): _type_ = api.llvm.GlobalVariable - __slots__ = () @staticmethod def new(module, ty, name, addrspace=0): @@ -1459,7 +1443,6 @@ class GlobalVariable(GlobalValue): thread_local = property(_get_thread_local, _set_thread_local) class Argument(Value): - __slots__ = () _type_ = api.llvm.Argument _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) @@ -1560,7 +1543,6 @@ class Argument(Value): return self._ptr.hasStructRetAttr() class Function(GlobalValue): - __slots__ = () _type_ = api.llvm.Function @staticmethod @@ -1699,7 +1681,6 @@ class Function(GlobalValue): #===----------------------------------------------------------------------=== class InlineAsm(Value): - __slots__ = () _type_ = api.llvm.InlineAsm @staticmethod @@ -1714,7 +1695,6 @@ class InlineAsm(Value): #===----------------------------------------------------------------------=== class MetaData(Value): - __slots__ = () _type_ = api.llvm.MDNode @staticmethod @@ -1771,7 +1751,6 @@ class MetaDataString(Value): class NamedMetaData(llvm.Wrapper): - __slots__ = () @staticmethod def get_or_insert(mod, name): @@ -1801,7 +1780,6 @@ class NamedMetaData(llvm.Wrapper): #===----------------------------------------------------------------------=== class Instruction(User): - __slots__ = () _type_ = api.llvm.Instruction @property @@ -1883,7 +1861,6 @@ class Instruction(User): class CallOrInvokeInstruction(Instruction): - __slots__ = () _type_ = api.llvm.CallInst, api.llvm.InvokeInst def _get_cc(self): @@ -1939,7 +1916,6 @@ class CallOrInvokeInstruction(Instruction): class PHINode(Instruction): - __slots__ = () _type_ = api.llvm.PHINode @property @@ -1957,7 +1933,6 @@ class PHINode(Instruction): class SwitchInstruction(Instruction): - __slots__ = () _type_ = api.llvm.SwitchInst def add_case(self, const, bblk): @@ -1965,7 +1940,6 @@ class SwitchInstruction(Instruction): class CompareInstruction(Instruction): - __slots__ = () _type_ = api.llvm.CmpInst @property @@ -1977,40 +1951,11 @@ class CompareInstruction(Instruction): return FCMPEnum.get(n) -class AllocaInstruction(Instruction): - __slots__ = () - _type_ = api.llvm.AllocaInst - - @property - def alignment(self): - return self._ptr.getAlignment() - - @alignment.setter - def alignment(self, n): - self._ptr.setAlignment(n) - - @property - def array_size(self): - return self._ptr.getArraySize() - - @array_size.setter - def array_size(self, value): - return self._ptr.setArraySize(value._ptr)._ptr - - @property - def is_array(self): - return self._ptr.isArrayAllocation() - - @property - def is_static(self): - return self._ptr.isStaticAlloca() - #===----------------------------------------------------------------------=== # Basic block #===----------------------------------------------------------------------=== class BasicBlock(Value): - __slots__ = () _type_ = api.llvm.BasicBlock def insert_before(self, name): @@ -2037,7 +1982,6 @@ class BasicBlock(Value): class _ValueFactory(object): - __slots__ = () cache = weakref.WeakValueDictionary() # value ID -> class map @@ -2066,8 +2010,7 @@ class _ValueFactory(object): VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, - VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction, - VALUE_INSTRUCTION + OPCODE_ALLOCA : AllocaInstruction, + VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction } @classmethod @@ -2114,7 +2057,6 @@ _atomic_orderings = { } class Builder(llvm.Wrapper): - __slots__ = () @staticmethod def new(basic_block): @@ -2276,6 +2218,7 @@ class Builder(llvm.Wrapper): # memory def malloc(self, ty, name=""): + context = api.llvm.getGlobalContext() allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) ity = allocsz.getType() malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, @@ -2289,6 +2232,7 @@ class Builder(llvm.Wrapper): return _make_value(inst) def malloc_array(self, ty, size, name=""): + context = api.llvm.getGlobalContext() allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) ity = allocsz.getType() malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, @@ -2301,13 +2245,12 @@ class Builder(llvm.Wrapper): inst = self._ptr.Insert(malloc, name) return _make_value(inst) - def alloca(self, ty, size=None, name=""): - sizeptr = size._ptr if size else None - return _make_value(self._ptr.CreateAlloca(ty._ptr, sizeptr, name)) + def alloca(self, ty, name=""): + intty = Type.int() + return _make_value(self._ptr.CreateAlloca(ty._ptr, None, name)) - @deprecated def alloca_array(self, ty, size, name=""): - return self.alloca(ty, size, name=name) + return _make_value(self._ptr.CreateAlloca(ty._ptr, size._ptr, name)) def free(self, ptr): free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) @@ -2394,20 +2337,15 @@ class Builder(llvm.Wrapper): # misc def extract_value(self, retval, idx, name=""): - if not isinstance(idx, (tuple, list)): - idx = [idx] - return _make_value(self._ptr.CreateExtractValue(retval._ptr, idx, - name)) + return _make_value(self._ptr.CreateExtractValue(retval._ptr, [idx], name)) # obsolete synonym for extract_value getresult = extract_value def insert_value(self, retval, rhs, idx, name=""): - if not isinstance(idx, (tuple, list)): - idx = [idx] return _make_value(self._ptr.CreateInsertValue(retval._ptr, rhs._ptr, - idx, + [idx], name)) def phi(self, ty, name=""): diff --git a/llvm/deprecated.py b/llvm/deprecated.py deleted file mode 100644 index 6db5fe7..0000000 --- a/llvm/deprecated.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Shameless borrowed from Smart_deprecation_warnings -https://wiki.python.org/moin/PythonDecoratorLibrary -""" - -import warnings -import functools - - -def deprecated(func): - """This is a decorator which can be used to mark functions - as deprecated. It will result in a warning being emitted - when the function is used.""" - - @functools.wraps(func) - def new_func(*args, **kwargs): - warnings.warn_explicit( - "Call to deprecated function %s." % (func.__name__,), - category=DeprecationWarning, - filename=func.func_code.co_filename, - lineno=func.func_code.co_firstlineno + 1 - ) - return func(*args, **kwargs) - - return new_func diff --git a/llvm/ee.py b/llvm/ee.py index f615b61..c687eaa 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -238,27 +238,3 @@ def dylib_add_symbol(name, ptr): def dylib_address_of_symbol(name): return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(name) - -def dylib_import_library(filename): - """Permanently import a dynamic library. - - Returns a DynamicLibrary object - - Raises RuntimeError - """ - return DynamicLibrary(filename) - - -class DynamicLibrary(object): - def __init__(self, filename): - """ - Raises RuntimeError - """ - self._ptr = api.llvm.sys.DynamicLibrary.getPermanentLibrary( - filename) - - def get_address_of_symbol(self, symbol): - """ - Get the address of `symbol` (str) as integer - """ - return self._ptr.getAddressOfSymbol(symbol) diff --git a/llvm/passes.py b/llvm/passes.py index e5ed085..0a4c524 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -80,15 +80,6 @@ class PassManagerBuilder(llvm.Wrapper): self._ptr.BBVectorize = enable vectorize = bbvectorize - - @property - def slpvectorize(self): - return self._ptr.SLPVectorize - - @slpvectorize.setter - def slpvectorize(self, enable): - self._ptr.SLPVectorize = enable - else: @property def vectorize(self): @@ -320,15 +311,13 @@ class TargetTransformInfo(Pass): # Helpers #===----------------------------------------------------------------------=== -def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False, - slp_vectorize=False, vectorize=False, - inline_threshold=None, pm=True, fpm=True, mod=None): +def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False, + inline_threshold=2000, pm=True, fpm=True, mod=None): ''' tm --- The TargetMachine for which the passes are optimizing for. The TargetMachine must stay alive until the pass managers are removed. opt --- [0-3] Optimization level. Default to 2. - size --- [0-2] Optimize for size. Default to 0. loop_vectorize --- [boolean] Whether to use loop-vectorizer. vectorize --- [boolean] Whether to use basic-block vectorizer. inline_threshold --- [int] Threshold for the inliner. @@ -337,18 +326,6 @@ def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False, fpm --- [boolean] Whether to build a function-level pass-manager. mod --- [Module] The module object for the FunctionPassManager. ''' - if inline_threshold is None: - if 0 < opt < 3: - inline_threshold = 225 - - if size == 1: - inline_threshold = 75 - elif size == 2: - inline_threshold = 25 - - if opt >= 3: - inline_threshold = 275 - if pm: pm = PassManager.new() if fpm: @@ -361,27 +338,22 @@ def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False, pmb.opt_level = opt pmb.vectorize = vectorize pmb.loop_vectorize = loop_vectorize - if llvm.version >= (3, 3): - pmb.slp_vectorize = slp_vectorize if inline_threshold: pmb.use_inliner_with_threshold(inline_threshold) if pm: pm.add(tm.target_data.clone()) pm.add(TargetLibraryInfo.new(tm.triple)) - if llvm.version <= (3, 2): + if llvm.version == (3, 2): pm.add(TargetTransformInfo.new(tm)) - else: - tm.add_analysis_passes(pm) pmb.populate(pm) if fpm: fpm.add(tm.target_data.clone()) fpm.add(TargetLibraryInfo.new(tm.triple)) - if llvm.version <= (3, 2): + if llvm.version == (3, 2): fpm.add(TargetTransformInfo.new(tm)) - else: - tm.add_analysis_passes(fpm) pmb.populate(fpm) + fpm.initialize() from collections import namedtuple return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) diff --git a/llvm/target.py b/llvm/target.py index f68b023..e70fd1b 100644 --- a/llvm/target.py +++ b/llvm/target.py @@ -191,10 +191,6 @@ class TargetMachine(llvm.Wrapper): def target(self): return self._ptr.getTarget() - if llvm.version >= (3, 3): - def add_analysis_passes(self, pm): - self._ptr.addAnalysisPasses(pm._ptr) - if llvm.version >= (3, 4): @property def reg_info(self): diff --git a/llvm/tests/__init__.py b/llvm/tests/__init__.py index 0bc4223..483201b 100644 --- a/llvm/tests/__init__.py +++ b/llvm/tests/__init__.py @@ -12,7 +12,7 @@ tests = [] # stores unittest.TestCase objects isolated_tests = [] # stores modue name -def run(verbosity=1, run_isolated=True): +def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + llvm.__version__) print(sys.version) @@ -37,32 +37,23 @@ def run(verbosity=1, run_isolated=True): if sys.version_info[:2] > (2, 6): kwargs['buffer'] = True runner = unittest.TextTestRunner(**kwargs) + testresult = runner.run(suite) - try: - from guppy import hpy - except ImportError: - testresult = runner.run(suite) - else: - hp = hpy() - hp.setref() - testresult = runner.run(suite) - print(hp.heap()) - - if testresult and run_isolated: + if testresult: # Run isolated tests print("run isolated tests".center(80, '-')) for test in isolated_tests: print(('testing %s' % test).center(80)) - cmd = [sys.executable, '-m', test] - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - for line in p.stdout: - print(line.decode('utf8'), end='') - p.wait() - if p.returncode: - raise Exception("%s returned: %d" % (test, p.returncode)) + cmd = [sys.executable, '-m', test] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + for line in p.stdout: + print(line, end='') + p.wait() + if p.returncode: + raise Exception("%s returned: %d" % p.returncode) return testresult diff --git a/llvm/tests/test_abi.py b/llvm/tests/test_abi.py new file mode 100644 index 0000000..35fc269 --- /dev/null +++ b/llvm/tests/test_abi.py @@ -0,0 +1,28 @@ +from __future__ import print_function +import unittest +from llvm.core import Type +from llvm.ee import TargetMachine +from llvm.abi import DefaultABIInfo +from .support import TestCase, tests + +class TestDefaultABIArgInfo(TestCase): + '''Simply exercise the API + ''' + def test_abi_int(self): + tm = TargetMachine.new() + td = tm.target_data.clone() + abiinfo = DefaultABIInfo(td) + abiinfo.compute_info(Type.void(), [Type.int(1), Type.int(8), + Type.int(16), Type.int(32), + Type.int(64)]) + print(abiinfo.arg_infos) + print(abiinfo.return_info) + + abiinfo.compute_info(Type.int(32), []) + print(abiinfo.arg_infos) + print(abiinfo.return_info) + +tests.append(TestDefaultABIArgInfo) + +if __name__ == '__main__': + unittest.main() diff --git a/llvm/tests/test_alloca.py b/llvm/tests/test_alloca.py deleted file mode 100644 index 60e3cf5..0000000 --- a/llvm/tests/test_alloca.py +++ /dev/null @@ -1,24 +0,0 @@ -import unittest -from llvm.core import Type, Module, Builder, Constant -from .support import TestCase, tests - -class TestAlloca(TestCase): - def test_alloca_alignment(self): - m = Module.new('') - f = m.add_function(Type.function(Type.void(), []), "foo") - b = Builder.new(f.append_basic_block('')) - inst = b.alloca(Type.int(32)) - inst.alignment = 4 - b.ret_void() - m.verify() - - self.assertTrue(inst.is_static) - self.assertFalse(inst.is_array) - self.assertEqual(inst.alignment, 4) - self.assertEqual(str(inst.array_size), 'i32 1') - -tests.append(TestAlloca) - -if __name__ == '__main__': - unittest.main() - diff --git a/llvm/tests/test_native.py b/llvm/tests/test_native.py index 04dde76..63eab5a 100644 --- a/llvm/tests/test_native.py +++ b/llvm/tests/test_native.py @@ -6,9 +6,8 @@ import subprocess import tempfile from distutils.spawn import find_executable from llvm.core import (Module, Type, Builder, Constant) -from .support import TestCase, IS_PY3K, tests, skip_if +from .support import TestCase, IS_PY3K, tests -@skip_if(sys.platform in ('win32', 'darwin')) class TestNative(TestCase): def setUp(self): @@ -61,10 +60,10 @@ class TestNative(TestCase): self._compile(src) def test_object(self): - ''' - Note: Older Darwin with GCC will report missing _main symbol when - compile the object file to an executable. - ''' + # if sys.platform == 'darwin': + # # skip this test on MacOSX for now + # return + m = self._make_module() output = m.to_native_object() @@ -74,7 +73,8 @@ class TestNative(TestCase): self._compile(src) -tests.append(TestNative) +if sys.platform != 'win32': + tests.append(TestNative) if __name__ == '__main__': unittest.main() diff --git a/llvm/tests/test_struct.py b/llvm/tests/test_struct.py index 8d61111..3783a8c 100644 --- a/llvm/tests/test_struct.py +++ b/llvm/tests/test_struct.py @@ -1,5 +1,5 @@ import unittest -from llvm.core import Type, Module, Builder, Constant +from llvm.core import Type from .support import TestCase, tests class TestStruct(TestCase): @@ -8,19 +8,6 @@ class TestStruct(TestCase): tb = Type.struct([Type.int(32), Type.float()]) self.assertTrue(ta.is_layout_identical(tb)) - def test_struct_extract_value_2d(self): - ta = Type.struct([Type.int(32), Type.float()]) - tb = Type.struct([ta, Type.float()]) - m = Module.new('') - f = m.add_function(Type.function(Type.void(), []), "foo") - b = Builder.new(f.append_basic_block('')) - v = Constant.undef(tb) - ins = b.insert_value(v, Constant.real(Type.float(), 1.234), [0, 1]) - ext = b.extract_value(ins, [0, 1]) - b.ret_void() - m.verify() - self.assertEqual(str(ext), 'float 0x3FF3BE76C0000000') - tests.append(TestStruct) if __name__ == '__main__': diff --git a/llvm/utils/__init__.py b/llvm/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/llvm/utils/check_intrinsics.py b/llvm/utils/check_intrinsics.py deleted file mode 100644 index 702dae3..0000000 --- a/llvm/utils/check_intrinsics.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import print_function, absolute_import -import sys -from llvm.core import Type, Function, Builder, Module -import llvm.core as lc -import llvm.ee as le -import multiprocessing -from ctypes import * - -INTRINSICS = {} - -CTYPES_MAP = { - Type.int(): c_int32, - Type.int(64): c_int64, - Type.float(): c_float, - Type.double(): c_double, -} - - -def register(name, retty, *args): - def wrap(fn): - INTRINSICS[name] = (retty, args), fn - return fn - return wrap - - -def intr_impl(intrcode, *types): - def impl(module, builder, args): - intr = Function.intrinsic(module, intrcode, types) - r = builder.call(intr, args) - return r - return impl - - -register("llvm.powi.f64", Type.double(), Type.double(), Type.int())\ - (intr_impl(lc.INTR_POWI, Type.double())) - -register("llvm.powi.f32", Type.float(), Type.float(), Type.int())\ - (intr_impl(lc.INTR_POWI, Type.float())) - -register("llvm.pow.f64", Type.double(), Type.double(), Type.double())\ - (intr_impl(lc.INTR_POW, Type.double())) - -register("llvm.pow.f32", Type.float(), Type.float(), Type.float())\ - (intr_impl(lc.INTR_POW, Type.float())) - -register("llvm.sin.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_SIN, Type.double())) - -register("llvm.sin.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_SIN, Type.float())) - -register("llvm.cos.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_COS, Type.double())) - -register("llvm.cos.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_COS, Type.float())) - -register("llvm.log.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_LOG, Type.double())) - -register("llvm.log.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_LOG, Type.float())) - -register("llvm.log2.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_LOG2, Type.double())) - -register("llvm.log2.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_LOG2, Type.float())) - -register("llvm.log10.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_LOG10, Type.double())) - -register("llvm.log10.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_LOG10, Type.float())) - -register("llvm.sqrt.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_SQRT, Type.double())) - -register("llvm.sqrt.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_SQRT, Type.float())) - -register("llvm.exp.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_EXP, Type.double())) - -register("llvm.exp.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_EXP, Type.float())) - -register("llvm.exp2.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_EXP2, Type.double())) - -register("llvm.exp2.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_EXP2, Type.float())) - -register("llvm.fabs.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_FABS, Type.double())) - -register("llvm.fabs.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_FABS, Type.float())) - -register("llvm.floor.f64", Type.double(), Type.double())\ - (intr_impl(lc.INTR_FLOOR, Type.double())) - -register("llvm.floor.f32", Type.float(), Type.float())\ - (intr_impl(lc.INTR_FLOOR, Type.float())) - - -def build_test(name): - (retty, args), impl = INTRINSICS[name] - module = Module.new("test.%s" % name) - fn = module.add_function(Type.function(retty, args), name="test_%s" % name) - builder = Builder.new(fn.append_basic_block("")) - retval = impl(module, builder, fn.args) - builder.ret(retval) - fn.verify() - module.verify() - return module, fn - - -def run_test(name): - module, fn = build_test(name) - eb = le.EngineBuilder.new(module).mcjit(True) - engine = eb.create() - ptr = engine.get_pointer_to_function(fn) - - argtys = fn.type.pointee.args - retty = fn.type.pointee.return_type - cargtys = [CTYPES_MAP[a] for a in argtys] - cretty = CTYPES_MAP[retty] - cfunc = CFUNCTYPE(cretty, *cargtys)(ptr) - args = [1] * len(cargtys) - cfunc(*args) - - -def spawner(name): - print("Testing %s" % name) - proc = multiprocessing.Process(target=run_test, args=(name,)) - - print('-' * 80) - proc.start() - proc.join() - - if proc.exitcode != 0: - print("FAILED") - ok = False - else: - print("PASSED") - ok = True - print('=' * 80) - print() - - return ok - -USAGE = """ -Args: [name] - -name: intrinsic name to test - -If no name is given, test all intrinsics. - -""" - - -def main(argv=()): - if len(argv) == 1: - intrname = argv[1] - spawner(intrname) - elif not argv: - failed = [] - for name in sorted(INTRINSICS): - if not spawner(name): - failed.append(name) - - print("Summary:") - for name in failed: - print("%s failed" % name) - else: - print(USAGE) - - -if __name__ == '__main__': - main(argv=sys.argv[1:]) diff --git a/llvm/workaround/avx_support.py b/llvm/workaround/avx_support.py index 4c65dc5..0b1c2da 100644 --- a/llvm/workaround/avx_support.py +++ b/llvm/workaround/avx_support.py @@ -12,11 +12,7 @@ http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf """ -import sys -import os -import subprocess -import contextlib - +import sys, os, subprocess def detect_avx_support(option='detect'): '''Detect AVX support''' @@ -40,25 +36,13 @@ def detect_unix_like(): except IOError: return False - with contextlib.closing(info): - for line in info: - if line.lstrip().startswith('flags'): - features = line.split() - if 'avx' in features and 'xsave' in features: - # enable AVX if flags contain AVX - return True - return False - - -@contextlib.contextmanager -def _close_popen(popen): - if sys.version_info[0] >= 3: - with popen: - yield - else: - yield - popen.stdout.close() - + for line in info: + if line.lstrip().startswith('flags'): + features = line.split() + if 'avx' in features and 'xsave' in features: + # enable AVX if flags contain AVX + return True + return False def detect_osx_like(): try: @@ -66,11 +50,9 @@ def detect_osx_like(): stdout=subprocess.PIPE) except OSError: return False - - with _close_popen(info): - features = info.stdout.read().decode('UTF8') - features = features.split() - return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features + features = info.stdout.read().decode('UTF8') + features = features.split() + return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features if __name__ == '__main__': diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index a2c0bda..eaabd67 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -349,7 +349,7 @@ class CBuilder(object): elif not isinstance(count, lc.Value): count = self.constant(types.int, count).value - ptr = self.builder.alloca(ty, size=count, name=name) + ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) def ret(self, val=None): diff --git a/llvmpy/capsule.cpp b/llvmpy/capsule.cpp index 5e0279d..561b28a 100644 --- a/llvmpy/capsule.cpp +++ b/llvmpy/capsule.cpp @@ -1,95 +1,55 @@ #include -#include #include #include #include -#include -#include -#include - -static PyObject* TheAPIModule = NULL; -static PyObject* TheCapsuleModule = NULL; -static PyObject* TheCapsuleClass = NULL; -static PyObject* TheWrapperClass = NULL; -static PyObject* TheCache = NULL; -static PyObject* TheAddrDtorDict = NULL; -static PyObject* TheClassesDict = NULL; -static PyObject* TheAddrRefCt = NULL; -static PyObject* ConstantOne = NULL; -static PyObject* TheDowncastModule = NULL; static -PyObject* GetAPIModule(){ - if (NULL == TheAPIModule) - TheAPIModule = PyImport_ImportModule("llvmpy._api"); - return TheAPIModule; +PyObject* getName(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + const char* name = PyCapsule_GetName(obj); + if (!name) return NULL; + + return PyString_FromString(name); } static -PyObject* GetCapsuleModule(){ - if (NULL == TheCapsuleModule) - TheCapsuleModule = PyImport_ImportModule("llvmpy.capsule"); - return TheCapsuleModule; +PyObject* getPointer(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj)); + if (!pointer) return NULL; + + return PyLong_FromVoidPtr(pointer); } static -PyObject* GetCapsuleClass() { - if (NULL == TheCapsuleClass) - TheCapsuleClass = PyObject_GetAttrString(GetCapsuleModule(), - "Capsule"); - return TheCapsuleClass; +PyObject* check(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)){ + return NULL; + } + if (PyCapsule_CheckExact(obj)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } } -static -PyObject* GetWrapperClass() { - if (NULL == TheWrapperClass) - TheWrapperClass = PyObject_GetAttrString(GetCapsuleModule(), - "Wrapper"); - return TheWrapperClass; -} +// ------------------ +// PyCapsule Context +// ------------------ static -PyObject* GetCache() { - if (NULL == TheCache) - TheCache = PyObject_GetAttrString(GetCapsuleModule(), "_cache"); - return TheCache; -} - -static -PyObject* GetAddrDtorDict() { - if (NULL == TheAddrDtorDict) - TheAddrDtorDict = PyObject_GetAttrString(GetCapsuleModule(), - "_addr2dtor"); - return TheAddrDtorDict; -} - -static -PyObject* GetClassesDict() { - if (NULL == TheClassesDict) - TheClassesDict = PyObject_GetAttrString(GetCapsuleModule(), - "_pyclasses"); - return TheClassesDict; -} - -static -PyObject* GetAddrRefCt() { - if (NULL == TheAddrRefCt) - TheAddrRefCt = PyObject_GetAttrString(GetCapsuleModule(), - "_addr2refct"); - return TheAddrRefCt; -} - -static -PyObject* GetDowncastModule() { - if (NULL == TheDowncastModule) - TheDowncastModule = PyObject_GetAttrString(GetAPIModule(), - "downcast"); - return TheDowncastModule; - -} - -static -CapsuleContext* GetContext(PyObject *obj) { +CapsuleContext* getContext(PyObject* self, PyObject* args) { + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return NULL; + } void* context = PyCapsule_GetContext(obj); if (!context) { PyErr_SetString(PyExc_TypeError, "PyCapsule has no context."); @@ -99,8 +59,9 @@ CapsuleContext* GetContext(PyObject *obj) { } static -PyObject* GetClassName(PyObject* obj) { - CapsuleContext* context = GetContext(obj); +PyObject* getClassName(PyObject* self, PyObject* args) { + CapsuleContext* context = getContext(self, args); + //Assert(context->_magic == 0xdead); if (!context) { return NULL; } else { @@ -108,476 +69,6 @@ PyObject* GetClassName(PyObject* obj) { } } -static -PyObject* getClassName(PyObject* self, PyObject* args) { - PyObject* obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - return GetClassName(obj); -} - -static -PyObject* GetName(PyObject* obj) { - const char* name = PyCapsule_GetName(obj); - if (!name) return NULL; - return PyString_FromString(name); -} - -static -PyObject* getName(PyObject* self, PyObject* args) { - PyObject* obj; - if (!PyArg_ParseTuple(args, "O", &obj)){ - return NULL; - } - return GetName(obj); -} - -static -PyObject* GetPointer(PyObject* obj){ - void *pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj)); - if (!pointer) return NULL; - return PyLong_FromVoidPtr(pointer); -} - -static -PyObject* getPointer(PyObject* self, PyObject* args) { - PyObject* obj; - if (!PyArg_ParseTuple(args, "O", &obj)){ - return NULL; - } - return GetPointer(obj); -} - -static -bool Check(PyObject* obj){ - return PyCapsule_CheckExact(obj); -} - -static -PyObject* check(PyObject* self, PyObject* args) { - PyObject* obj; - if (!PyArg_ParseTuple(args, "O", &obj)){ - return NULL; - } - if (Check(obj)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - - -static PyObject* Unwrap(PyObject* obj) { - if (PyObject_IsInstance(obj, GetWrapperClass())) { - return PyObject_GetAttrString(obj, "_ptr"); - } else { - Py_INCREF(obj); - return obj; - } -} - -/* -Unwrap a Wrapper instance into the underlying PyCapsule. -If `obj` is not a Wrapper instance, returns `obj`. -*/ -static PyObject* unwrap(PyObject* self, PyObject* args) { - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - return Unwrap(obj); -} - -static bool HasOwnership(PyObject* obj) { - PyObject* addr = GetPointer(obj); - PyObject* name = GetName(obj); - auto_pyobject nameaddr = PyTuple_Pack(2, name, addr); - PyObject* dtor = PyDict_GetItem(GetAddrDtorDict(), *nameaddr); - if (!dtor || dtor == Py_None) { - return false; - } else { - return true; - } -} - -static PyObject* has_ownership(PyObject* self, PyObject* args) { - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - if (HasOwnership(obj)) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static -void NormalizeString(std::ostream &os, const char* str) { - for(; *str; ++str){ - if (*str == ':') { - os << '_'; - if(*(str + 1) == ':') { ++str; } - } else { - os << *str; - } - } -} - -static -PyObject* WrapCore(PyObject *oldCap, bool owned) { - auto_pyobject cap = PyObject_CallFunctionObjArgs(GetCapsuleClass(), oldCap, - NULL); - auto_pyobject cls = PyObject_CallMethod(*cap, "get_class", ""); - auto_pyobject addr = GetPointer(oldCap); - auto_pyobject name = GetName(oldCap); - - // look up cached object - auto_pyobject cache_cls = PyObject_GetItem(GetCache(), *cls); - Assert(*cache_cls); - int addr_in_cache = PyMapping_HasKey(*cache_cls, *addr); - - PyObject* obj = NULL; - if (addr_in_cache) { - obj = PyObject_GetItem(*cache_cls, *addr); - } else { - if (!owned) { - auto_pyobject hasDtor = PyObject_CallMethod(*cls, "_has_dtor", ""); - if (PyObject_IsTrue(*hasDtor)) { - auto_pyobject key = PyTuple_Pack(2, *name, *addr); - auto_pyobject val = PyObject_GetAttrString(*cls, "_delete_"); - - int ok = PyDict_SetItem(GetAddrDtorDict(), *key, *val); - Assert(ok != -1); - } - } - obj = PyObject_CallMethod(*cap, "instantiate", ""); - int ok = PyObject_SetItem(*cache_cls, *addr, obj); - Assert(ok != -1); - } - - Assert(obj); - return obj; -} - -static -PyObject* Wrap(PyObject* cap, bool owned){ - if (!Check(cap)) { - if (PyList_Check(cap)) { - const int N = PyList_Size(cap); - PyObject* result = PyList_New(N); - - for (int i = 0; i < N; ++i){ - PyObject* item = PyList_GetItem(cap, i); - if (!item) - return NULL; - PyObject* out = Wrap(item, false); - if (!out) return NULL; - if (-1 == PyList_SetItem(result, i, out)) - return NULL; - } - - return result; - } else { - Py_INCREF(cap); - return cap; - } - } - - return WrapCore(cap, owned); -} - - -static -PyObject* wrap(PyObject* self, PyObject* args) { - PyObject* obj; - PyObject* owned = NULL; - if (!PyArg_ParseTuple(args, "O|O", &obj, &owned)) { - return NULL; - } - bool ownedFlag = false; - if (owned) { - ownedFlag = PyObject_IsTrue(owned); - } - return Wrap(obj, ownedFlag); -} - -static -PyObject* downcast(PyObject* self, PyObject* args) { - PyObject *obj, *cls; - if (!PyArg_ParseTuple(args, "OO", &obj, &cls)) { - return NULL; - } - - auto_pyobject objType = PyObject_Type(obj); - - if (*objType == cls) { - Py_INCREF(obj); - return obj; - } - - PyObject* apiModule = GetAPIModule(); - - auto_pyobject fromTy = PyObject_GetAttrString(obj, "_llvm_type_"); - auto_pyobject toTy = PyObject_GetAttrString(cls, "_llvm_type_"); - - std::ostringstream oss; - - auto_pyobject fromTyStr = PyObject_Str(*fromTy); - auto_pyobject toTyStr = PyObject_Str(*toTy); - - const char * fromCS = PyString_AsString(*fromTyStr); - const char * toCS = PyString_AsString(*toTyStr); - - oss << "downcast_"; - NormalizeString(oss, fromCS); - oss << "_to_"; - NormalizeString(oss, toCS); - std::string fname = oss.str(); - - auto_pyobject caster = PyObject_GetAttrString(GetDowncastModule(), - fname.c_str()); - - if (!caster) { - std::ostringstream oss; - oss << "Downcast from " << fromCS << " to " << toCS; - std::string errmsg = oss.str(); - PyErr_SetString(PyExc_TypeError, errmsg.c_str()); - return NULL; - } - - auto_pyobject oldObj = Unwrap(obj); - auto_pyobject newObj = PyObject_CallFunctionObjArgs(*caster, *oldObj, - NULL); - - bool used_to_own = HasOwnership(*oldObj); - - PyObject *result = Wrap(*newObj, !used_to_own); - - int status = PyObject_Not(result); - switch(status) { - case 0: - return result; - case 1: - default: - PyErr_SetString(PyExc_ValueError, "Downcast failed"); - Py_XDECREF(result); - return NULL; - } -} - -/////////////////////////////////////////////////////////////////////////////// - -struct CapsuleObject { - PyObject_HEAD; - PyObject *capsule; -}; - -static -void Capsule_dealloc(CapsuleObject* self) { - Py_XDECREF(self->capsule); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static -int Capsule_init(CapsuleObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *cap; - if (!PyArg_ParseTuple(args, "O", &cap)) { - return -1; - } - - if (!Check(cap)) { - PyErr_SetString(PyExc_TypeError, "Expected PyCapsule object"); - return -1; - } - - Py_INCREF(cap); - self->capsule = cap; - - PyObject* addr2refct = GetAddrRefCt(); - - auto_pyobject ptr = GetPointer(self->capsule); - auto_pyobject refct = PyObject_GetItem(addr2refct, *ptr); - auto_pyobject inc = PyNumber_InPlaceAdd(*refct, ConstantOne); - return PyObject_SetItem(addr2refct, *ptr, *inc); -} - -static -PyObject* Capsule_getclassname(CapsuleObject* self, void *closure) { - return GetClassName(self->capsule); -} - -static -PyObject* Capsule_getname(CapsuleObject* self, void *closure) { - return GetName(self->capsule); -} - -static -PyObject* Capsule_getpointer(CapsuleObject* self, void *closure) { - return GetPointer(self->capsule); -} - - -static -PyObject* Capsule_GetClass(CapsuleObject *self){ - PyObject *pycls = GetClassesDict(); - auto_pyobject key = GetClassName(self->capsule); - return PyDict_GetItem(pycls, *key); // borrowed reference -} - -static -PyObject* Capsule_get_class(CapsuleObject* self, PyObject* args) { - PyObject* out = Capsule_GetClass(self); - Py_XINCREF(out); - return out; -} - -static -PyObject* Capsule_instantiate(CapsuleObject* self, PyObject* args) { - return PyObject_CallFunctionObjArgs(Capsule_GetClass(self), self, NULL); -} - -/// Rotate Right -static unsigned long RotR(unsigned long hash, int offset){ - if (offset == 0) return hash; - - unsigned long out = hash << (sizeof(hash) * 8 - offset); - out |= hash >> offset; - return out; -} - - -/* -This is called everytime an object is returned from LLVM. -It derserves to be optimized to reduce unnecessary Python object allocation. -The following implements a simple hash function that uses XOR and -right-rotation. -*/ -static -long Capsule_hash(CapsuleObject *self) { - const char* name = PyCapsule_GetName(self->capsule); - void *pointer = PyCapsule_GetPointer(self->capsule, name); - - unsigned long hash = 0xabcd1234 ^ (unsigned long)pointer; - - // The first loop accounts for the different LLVM class name and the - // length of the name. - for(const char* p = name; *p != '\0'; ++p) { - hash ^= *p; - hash = RotR(hash, 11); - } - - // The second loop accounts for the pointer identity. - for(int i = 0; i capsule, - PyCapsule_GetName(a->capsule)); - void* pb = PyCapsule_GetPointer(b->capsule, - PyCapsule_GetName(b->capsule)); - return pa == pb; - } - return false; -} - -static -PyObject* Capsule_richcmp(PyObject *a, PyObject *b, int op) { - bool ret = Capsule_eq(a, b); - switch(op) { - case Py_EQ: break; - case Py_NE: ret = !ret; break; - default: - return Py_NotImplemented; - } - if (ret) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -static PyMemberDef Capsule_members[] = { - {"capsule", T_OBJECT_EX, offsetof(CapsuleObject, capsule), READONLY, "capsule"}, - { NULL }, -}; - -static PyMethodDef Capsule_methods[] = { - { "get_class", (PyCFunction)Capsule_get_class, METH_NOARGS, - "Get Capsule class"}, - { "instantiate", (PyCFunction)Capsule_instantiate, METH_NOARGS, - "create a new instance"}, - { NULL }, -}; - -static PyGetSetDef Capsule_getseters[] = { - {"classname", (getter)Capsule_getclassname, NULL, "class name", NULL}, - {"name", (getter)Capsule_getname, NULL, "name", NULL}, - {"pointer", (getter)Capsule_getpointer, NULL, "pointer", NULL}, - { NULL }, -}; - -static PyTypeObject CapsuleType = { -#if (PY_MAJOR_VERSION < 3) - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ -#else - PyVarObject_HEAD_INIT(NULL, 0) -#endif - "_capsule.Capsule", /*tp_name*/ - sizeof(CapsuleObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Capsule_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)Capsule_hash, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - "Capsule object", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)Capsule_richcmp, /*tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Capsule_methods, /* tp_methods */ - Capsule_members, /* tp_members */ - Capsule_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Capsule_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - - -/////////////////////////////////////////////////////////////////////////////// - static PyMethodDef core_methods[] = { #define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } @@ -585,10 +76,6 @@ static PyMethodDef core_methods[] = { declmethod(getPointer), declmethod(check), declmethod(getClassName), - declmethod(unwrap), - declmethod(wrap), - declmethod(has_ownership), - declmethod(downcast), { NULL }, #undef declmethod }; @@ -619,21 +106,10 @@ extern "C" { #else PyObject *module = Py_InitModule("_capsule", core_methods); #endif - if (module == NULL){ + if (module == NULL) INITERROR; - } - - if (module) { - CapsuleType.tp_new = PyType_GenericNew; - if (PyType_Ready(&CapsuleType) < 0) { - INITERROR; - } - Py_INCREF(&CapsuleType); - PyModule_AddObject(module, "Capsule", (PyObject*)(&CapsuleType)); - - ConstantOne = PyInt_FromLong(1); - } #if PY_MAJOR_VERSION >= 3 + return module; #endif } diff --git a/llvmpy/capsule.py b/llvmpy/capsule.py index 3fb9a39..9de0571 100644 --- a/llvmpy/capsule.py +++ b/llvmpy/capsule.py @@ -1,27 +1,19 @@ -from weakref import WeakValueDictionary +from weakref import WeakKeyDictionary, WeakValueDictionary, ref from collections import defaultdict import logging -from llvmpy._capsule import (unwrap, has_ownership, downcast, wrap, - getClassName, getName, getPointer, Capsule) - - logger = logging.getLogger(__name__) NO_DEBUG = False - - def silent_logger(): ''' Silent logger for unless we have a error message. ''' - global NO_DEBUG logger.setLevel(logging.ERROR) NO_DEBUG = True # comment out the line below to re-enable logging at DEBUG level. silent_logger() - def set_debug(enabled): ''' Side-effect: configure logger with it is not configured. @@ -36,63 +28,79 @@ def set_debug(enabled): else: logger.setLevel(logging.WARNING) +def _capsule_weakref_dtor(item): + addr = item.pointer + name = item.name + _addr2refct[addr] -= 1 + refct = _addr2refct[addr] + assert refct >= 0, "RefCt drop below 0" + if refct == 0: + dtor = _addr2dtor.pop((name, addr), None) + if dtor is not None: + if not NO_DEBUG: + # Some globals in logger could be removed by python GC + # at interpreter teardown. + # That can cause exception raised and ignored message. + logger.debug('Destroy %s %s', name, hex(addr)) + dtor(item.capsule) -#class Capsule(object): -# "Wraps PyCapsule so that we can build weakref of it." -# from ._capsule import check, getClassName, getName, getPointer -# __slots__ = "capsule" -# -# def __init__(self, capsule): -# assert Capsule.valid(capsule) -# self.capsule = capsule -# -# #weak = WeakRef(self, _capsule_weakref_dtor) -# #weak.pointer = self.pointer -# #weak.capsule = capsule -# #weak.name = self.name -# #_capsule2weak[self] = weak -# _addr2refct[self.pointer] += 1 -# -# @property -# def classname(self): -# return self.getClassName(self.capsule) -# -# @property -# def name(self): -# return self.getName(self.capsule) -# -# @property -# def pointer(self): -# return self.getPointer(self.capsule) -# -# @staticmethod -# def valid(capsule): -# return Capsule.check(capsule) -# -# def get_class(self): -# return _pyclasses[self.classname] -# -# def instantiate(self): -# cls = self.get_class() -# return cls(self) -# -# def __eq__(self, other): -# if isinstance(other, Capsule) and self.pointer == other.pointer: -# assert self.name == other.name -# return True -# else: -# return False -# -# def __hash__(self): -# return hash((self.pointer, self.name)) -# -# def __ne__(self, other): -# return not (self == other) +class Capsule(object): + "Wraps PyCapsule so that we can build weakref of it." + from ._capsule import check, getClassName, getName, getPointer + def __init__(self, capsule): + assert Capsule.valid(capsule) + self.capsule = capsule + + weak = WeakRef(self, _capsule_weakref_dtor) + weak.pointer = self.pointer + weak.capsule = capsule + weak.name = self.name + _capsule2weak[self] = weak + _addr2refct[self.pointer] += 1 + + @property + def classname(self): + return self.getClassName(self.capsule) + + @property + def name(self): + return self.getName(self.capsule) + + @property + def pointer(self): + return self.getPointer(self.capsule) + + @staticmethod + def valid(capsule): + return Capsule.check(capsule) + + def get_class(self): + return _pyclasses[self.classname] + + def instantiate(self): + cls = self.get_class() + return cls(self) + + def __eq__(self, other): + if self.pointer == other.pointer: + assert self.name == other.name + return True + else: + return False + + def __hash__(self): + return hash((self.pointer, self.name)) + + def __ne__(self, other): + return not (self == other) + +class WeakRef(ref): + pass _addr2refct = defaultdict(lambda: 0) -#_capsule2weak = WeakKeyDictionary() +_capsule2weak = WeakKeyDictionary() _addr2dtor = {} _pyclasses = {} @@ -100,16 +108,15 @@ _pyclasses = {} # NOTE: The same 'addr' may appear in multiple class bins. _cache = defaultdict(WeakValueDictionary) - def release_ownership(old): logger.debug('Release %s', old) - addr = getPointer(old) - name = getName(old) + addr = Capsule.getPointer(old) + name = Capsule.getName(old) if _addr2dtor.get((name, addr)) is None: - clsname = getClassName(old) + clsname = Capsule.getClassName(old) if not _pyclasses[clsname]._has_dtor(): return - # Guard duplicated release + # Guard duplicated release raise Exception("Already released") _addr2dtor[(name, addr)] = None @@ -119,86 +126,61 @@ def obtain_ownership(cap): if cls._has_dtor(): addr = cap.pointer name = cap.name - assert _addr2dtor[(name, addr)] is None + assert _addr2dtor[addr] is None _addr2dtor[(name, addr)] = cls._delete_ +def has_ownership(cap): + addr = Capsule.getPointer(cap) + name = Capsule.getName(cap) + return _addr2dtor.get((name, addr)) is not None -#def has_ownership(cap): -# addr = Capsule.getPointer(cap) -# name = Capsule.getName(cap) -# return _addr2dtor.get((name, addr)) is not None +def wrap(cap, owned=False): + '''Wrap a PyCapsule with the corresponding Wrapper class. + If `cap` is not a PyCapsule, returns `cap` + ''' + if not Capsule.valid(cap): + if isinstance(cap, list): + return list(map(wrap, cap)) + return cap # bypass if cap is not a PyCapsule and not a list + cap = Capsule(cap) + cls = cap.get_class() + addr = cap.pointer + name = cap.name + # lookup cached object + if cls in _cache and addr in _cache[cls]: + obj = _cache[cls][addr] + else: + if not owned and cls._has_dtor(): + _addr2dtor[(name, addr)] = cls._delete_ + obj = cap.instantiate() + _cache[cls][addr] = obj # cache it + return obj -#def wrap(cap, owned=False): -# '''Wrap a PyCapsule with the corresponding Wrapper class. -# If `cap` is not a PyCapsule, returns `cap` -# ''' -# if not Capsule.valid(cap): -# if isinstance(cap, list): -# return list(map(wrap, cap)) -# return cap # bypass if cap is not a PyCapsule and not a list -# -# cap = Capsule(cap) -# cls = cap.get_class() -# addr = cap.pointer -# name = cap.name -# # lookup cached object -# if cls in _cache and addr in _cache[cls]: -# obj = _cache[cls][addr] -# else: -# if not owned and cls._has_dtor(): -# _addr2dtor[(name, addr)] = cls._delete_ -# obj = cap.instantiate() -# _cache[cls][addr] = obj # cache it -# return obj - -#def unwrap(obj): +def unwrap(obj): '''Unwrap a Wrapper instance into the underlying PyCapsule. If `obj` is not a Wrapper instance, returns `obj`. ''' -# if isinstance(obj, Wrapper): -# return obj._ptr -# else: -# return obj + if isinstance(obj, Wrapper): + return obj._ptr + else: + return obj def register_class(clsname): def _wrapped(cls): _pyclasses[clsname] = cls return cls - return _wrapped class Wrapper(object): + __slots__ = '__capsule' def __init__(self, capsule): self.__capsule = capsule - def __del__(self): - if _addr2refct is None: - # System is tearing down - # No need to free anything - return - - item = self.__capsule - addr = item.pointer - name = item.name - - _addr2refct[addr] -= 1 - refct = _addr2refct[addr] - assert refct >= 0, "RefCt drop below 0" - if refct == 0: - dtor = _addr2dtor.pop((name, addr), None) - if dtor is not None: - if not NO_DEBUG: - # Some globals in logger could be removed by python GC - # at interpreter teardown. - # That can cause exception raised and ignored message. - logger.debug('Destroy %s %s', name, hex(addr)) - dtor(item.capsule) - @property def _capsule(self): return self.__capsule @@ -211,11 +193,10 @@ class Wrapper(object): return hash(self._capsule) def __eq__(self, other): - if isinstance(other, Wrapper): - return self._capsule == other._capsule + return self._capsule == other._capsule def __ne__(self, other): - return not (self == other) + return not(self == other) def _downcast(self, newcls): return downcast(self, newcls) @@ -224,25 +205,24 @@ class Wrapper(object): def _has_dtor(cls): return hasattr(cls, '_delete_') +def downcast(obj, cls): + from . import _api + if type(obj) is cls: + return obj + fromty = obj._llvm_type_ + toty = cls._llvm_type_ + logger.debug("Downcast %s to %s" , fromty, toty) + fname = 'downcast_%s_to_%s' % (fromty, toty) + fname = fname.replace('::', '_') + if not hasattr(_api.downcast, fname): + fmt = "Downcast from %s to %s is not supported" + raise TypeError(fmt % (fromty, toty)) + caster = getattr(_api.downcast, fname) + old = unwrap(obj) + new = caster(old) + used_to_own = has_ownership(old) + res = wrap(new, owned=not used_to_own) + if not res: + raise ValueError("Downcast failed") + return res -#def downcast(obj, cls): -# from . import _api -# -# if type(obj) is cls: -# return obj -# fromty = obj._llvm_type_ -# toty = cls._llvm_type_ -# logger.debug("Downcast %s to %s", fromty, toty) -# fname = 'downcast_%s_to_%s' % (fromty, toty) -# fname = fname.replace('::', '_') -# if not hasattr(_api.downcast, fname): -# fmt = "Downcast from %s to %s is not supported" -# raise TypeError(fmt % (fromty, toty)) -# caster = getattr(_api.downcast, fname) -# old = unwrap(obj) -# new = caster(old) -# used_to_own = has_ownership(old) -# res = wrap(new, owned=not used_to_own) -# if not res: -# raise ValueError("Downcast failed") -# return res diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 5a6d8f4..30e1614 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -1,4 +1,5 @@ import inspect, textwrap +import functools import codegen as cg import os @@ -7,12 +8,10 @@ namespaces = {} RESERVED = frozenset(['None']) - def makedir(directory): if not os.path.exists(directory): os.makedirs(directory) - class SubModule(object): def __init__(self): self.methods = [] @@ -294,10 +293,6 @@ class Class(SubModule, _Type): writer.println('@capsule.register_class("%s")' % self.fullname) with writer.block('class %(clsname)s(%(bases)s):' % locals()): writer.println('_llvm_type_ = "%s"' % self.fullname) - if self.bases: - writer.println('__slots__ = ()') - else: - writer.println('__slots__ = "__weakref__"') for enum in self.enums: enum.compile_py(writer) for meth in self.methods: @@ -404,7 +399,6 @@ class Enum(object): writer.println(fmt % locals()) writer.println() - class Method(object): _kind_ = 'meth' @@ -522,7 +516,6 @@ class Method(object): with writer.block('if len(%s) > %d:' % (unwrapped, i)): writer.release_ownership('%s[%d]' % (unwrapped, i)) - class CustomMethod(Method): def __init__(self, methodname, retty, *argtys): super(CustomMethod, self).__init__(retty, *argtys) @@ -601,7 +594,6 @@ class CustomFunction(Function): def fullname(self): return self.realname - class Destructor(Method): _kind_ = 'dtor' @@ -633,7 +625,6 @@ class Constructor(StaticMethod): ret = writer.declare(retty.fullname, stmt) return ret - class ref(_Type): def __init__(self, element): assert isinstance(element, Class), type(element) @@ -695,16 +686,13 @@ class ptr(_Type): return writer.pycapsule_new(val, self.element.capsule_name, self.element.fullname) - class ownedptr(ptr): pass - def const(ptr_or_ref): ptr_or_ref.const = True return ptr_or_ref - class cast(_Type): format = 'O' @@ -769,7 +757,6 @@ class CustomPythonMethod(object): for line in self.sourcelines: writer.println(line) - class CustomPythonStaticMethod(CustomPythonMethod): def compile_py(self, writer): writer.println('@staticmethod') @@ -858,7 +845,6 @@ class Attr(object): TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split() - def _parse_llvm_version(ver): import re m = re.compile(r'(\d+)\.(\d+)').match(ver) diff --git a/llvmpy/gen/gen.py b/llvmpy/gen/gen.py index bb408a1..cd63b68 100644 --- a/llvmpy/gen/gen.py +++ b/llvmpy/gen/gen.py @@ -9,7 +9,7 @@ extern "C" { #if (PY_MAJOR_VERSION >= 3) -PyMODINIT_FUNC +PyObject * PyInit_%(module)s(void) { PyObject *module = create_python_module("%(module)s", meth_%(ns)s); diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index bdd86d3..f8f7766 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -40,7 +40,7 @@ namespace extra{ using namespace llvm; - + class raw_svector_ostream_helper: public raw_svector_ostream { SmallVectorImpl *SV; public: @@ -85,7 +85,7 @@ PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { using extra::raw_svector_ostream_helper; using llvm::raw_svector_ostream; - + if (!PyArg_ParseTuple(args, "")) { return NULL; } @@ -99,7 +99,7 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args) { using llvm::Type; typedef llvm::SmallVector SmallVector_Type; - + SmallVector_Type* SV = new SmallVector_Type; Py_ssize_t size = PyTuple_Size(args); for (Py_ssize_t i = 0; i < size; ++i) { @@ -186,8 +186,8 @@ PyObject* iterator_to_pylist_deref(iterator begin, iterator end, { PyObject* list = PyList_New(0); for(; begin != end; ++begin) { - auto_pyobject cap = pycapsule_new(&*begin, capsuleName, className); - PyList_Append(list, *cap); + PyObject* cap = pycapsule_new(&*begin, capsuleName, className); + PyList_Append(list, cap); } return list; } @@ -198,8 +198,8 @@ PyObject* iterator_to_pylist(iterator begin, iterator end, { PyObject* list = PyList_New(0); for(; begin != end; ++begin) { - auto_pyobject cap = pycapsule_new(*begin, capsuleName, className); - PyList_Append(list, *cap); + PyObject* cap = pycapsule_new(*begin, capsuleName, className); + PyList_Append(list, cap); } return list; } @@ -420,7 +420,7 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE, PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?"); return NULL; } - + GenericValue* gv = static_cast( PyCapsule_GetPointer(obj, GVN)); @@ -575,11 +575,11 @@ PyObject* TargetMachine_addPassesToEmitFile( bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify); if (status) { StringRef sr = rso.str(); - auto_pyobject buf = PyString_FromStringAndSize(sr.data(), sr.size()); + PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size()); if (!buf) { return NULL; } - if (-1 == PyFile_WriteObject(*buf, Out, Py_PRINT_RAW)){ + if (-1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW)){ return NULL; } Py_RETURN_TRUE; @@ -626,7 +626,7 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker, if (! failed) { Py_RETURN_FALSE; } else { - + auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); if (NULL == callwrite(ErrMsg, *buf)){ return NULL; @@ -861,27 +861,6 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, } } -static -PyObject* DynamicLibrary_getPermanentLibrary(const char * Filename, - PyObject* ErrMsg = 0) -{ - using namespace llvm::sys; - std::string errmsg; - DynamicLibrary dylib = DynamicLibrary::getPermanentLibrary(Filename, &errmsg); - if (!dylib.isValid()) { - if (ErrMsg) { - auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (!callwrite(ErrMsg, *buf)) - return NULL; - } - PyErr_SetString(PyExc_RuntimeError, errmsg.c_str()); - return NULL; - } - return pycapsule_new(new DynamicLibrary(dylib), - "llvm::sys::DynamicLibrary", - "llvm::sys::DynamicLibrary"); -} - class PassRegistryEnumerator : public llvm::PassRegistrationListener{ public: PyObject* List; @@ -891,8 +870,7 @@ public: inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ PyObject* passArg = PyString_FromString(pass_info->getPassArgument()); PyObject* passName = PyString_FromString(pass_info->getPassName()); - auto_pyobject pair = Py_BuildValue("(OO)", passArg, passName); - PyList_Append(List, *pair); + PyList_Append(List, Py_BuildValue("(OO)", passArg, passName)); } }; @@ -1010,7 +988,7 @@ fail: } static -PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm, +PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm, llvm::MCInst &instr, const llvm::MemoryObject ®ion, uint64_t address @@ -1020,7 +998,7 @@ PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm, llvm::MCDisassembler::DecodeStatus status; size = 0; - status = disasm->getInstruction(instr, size, region, address, + status = disasm->getInstruction(instr, size, region, address, llvm::nulls(), llvm::nulls()); return Py_BuildValue("(i,i)", int(status), size); } @@ -1068,5 +1046,5 @@ PyObject* llvm_sys_isBigEndianHost() else Py_RETURN_FALSE; } -#endif +#endif diff --git a/llvmpy/src/BasicBlock.py b/llvmpy/src/BasicBlock.py index 3c82e17..6efe704 100644 --- a/llvmpy/src/BasicBlock.py +++ b/llvmpy/src/BasicBlock.py @@ -1,13 +1,12 @@ from binding import * from .namespace import llvm -from .Value import Function, BasicBlock, Value +from .Value import Function, BasicBlock from .Instruction import Instruction, TerminatorInst from .LLVMContext import LLVMContext from .ADT.StringRef import StringRef @BasicBlock class BasicBlock: - _downcast_ = Value Create = StaticMethod(ptr(BasicBlock), ref(LLVMContext), cast(str, StringRef), ptr(Function), diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index 585b7ec..2771015 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -346,9 +346,6 @@ class AllocaInst: isStaticAlloca = Method(cast(Bool, bool)) getArraySize = Method(ptr(Value)) getAllocatedType = Method(ptr(Type)) - getAlignment = Method(cast(Unsigned, int)) - setAlignment = Method(Void, cast(int, Unsigned)) - getArraySize = Method(ptr(Value)) @CastInst diff --git a/llvmpy/src/Support/DynamicLibrary.py b/llvmpy/src/Support/DynamicLibrary.py index e3b1d37..7dce97a 100644 --- a/llvmpy/src/Support/DynamicLibrary.py +++ b/llvmpy/src/Support/DynamicLibrary.py @@ -26,10 +26,3 @@ class DynamicLibrary: cast(str, StringRef), # symbolName cast(int, VoidPtr), # address ) - - getPermanentLibrary = CustomStaticMethod( - 'DynamicLibrary_getPermanentLibrary', - PyObjectPtr, - cast(str, ConstCharPtr), # filename - PyObjectPtr, # std::string * errmsg = 0 - ).require_only(1) diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index 1b52359..492d603 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -53,9 +53,6 @@ class TargetMachine: getVectorTargetTransformInfo = Method(const( ownedptr(VectorTargetTransformInfo))) - else: - addAnalysisPasses = Method(Void, ref(PassManagerBase)) - addPassesToEmitFile = Method(cast(bool, Bool), ref(PassManagerBase), ref(formatted_raw_ostream), diff --git a/setup.py b/setup.py index 08d59b6..15601ee 100644 --- a/setup.py +++ b/setup.py @@ -189,8 +189,7 @@ setup( 'llpython', 'llvm_array', 'llvmpy.api', 'llvmpy.api.llvm', - 'llvm.tests', - 'llvm.utils',], + 'llvm.tests',], package_data = {'llvm': ['llrt/*.ll']}, py_modules = ['llvmpy', 'llvmpy._capsule', diff --git a/test/inlineasm.py b/test/inlineasm.py index 26ee4b5..64a4cbe 100644 --- a/test/inlineasm.py +++ b/test/inlineasm.py @@ -3,7 +3,7 @@ # Import the llvm-py modules. from llvm import * from llvm.core import * -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase import logging import unittest diff --git a/test/loopvectorize.py b/test/loopvectorize.py index dc11cb3..2c12d5b 100644 --- a/test/loopvectorize.py +++ b/test/loopvectorize.py @@ -2,7 +2,7 @@ from llvm.core import * from llvm.passes import * from llvm.ee import * import llvm -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase from os.path import dirname, join as join_path diff --git a/test/metadata.py b/test/metadata.py index 0062bcc..3228159 100644 --- a/test/metadata.py +++ b/test/metadata.py @@ -1,7 +1,7 @@ from __future__ import print_function import unittest -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase from llvm.core import * class TestMetaData(TestCase): diff --git a/test/tbaa.py b/test/tbaa.py index 4a24de8..ad11081 100644 --- a/test/tbaa.py +++ b/test/tbaa.py @@ -1,6 +1,6 @@ from llvm.core import * from llvm.tbaa import * -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase import unittest class TestTBAABuilder(TestCase): diff --git a/test/test.py b/test/test.py index e23aca3..3b46281 100644 --- a/test/test.py +++ b/test/test.py @@ -7,7 +7,7 @@ import unittest, sys, logging from llvm import * from llvm.core import * -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase class TestModule(TestCase): diff --git a/test/test_debuginfo.py b/test/test_debuginfo.py index d31563c..b6a5d6f 100644 --- a/test/test_debuginfo.py +++ b/test/test_debuginfo.py @@ -4,7 +4,7 @@ import unittest import llvm.ee from llvm.core import * from llvm import _dwarf, debuginfo -from llvm.tests.support import TestCase +from llvm.test_llvmpy import TestCase class TestDebugInfo(TestCase):