Compare commits

..

2 commits

Author SHA1 Message Date
Siu Kwan Lam
0dc22f26a0 Begin to add C-ABI ArgInfo 2013-10-05 16:17:44 +08:00
Siu Kwan Lam
da55b76202 Add buildscript for devel branch 2013-10-05 14:03:13 +08:00
42 changed files with 553 additions and 1438 deletions

View file

@ -1,35 +1,5 @@
2014-04-28 0.12.5: 2013-8-28 0.12.0:
--------------------- --------------------
* 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:
---------------------
* update to LLVM 3.3 and maintain compatibility with LLVM 3.2 * 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 * add LLRT for minimal support for 64-bit divmod on 32-bit platform
* start to adopt MCJIT (not quite usable on win32) * start to adopt MCJIT (not quite usable on win32)

View file

@ -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 llvm *
recursive-include llvmpy *
recursive-include www * recursive-include www *
recursive-include test * recursive-include test *
recursive-include tools * recursive-include tools *

View file

@ -30,13 +30,10 @@ Quickstart
to separate your custom build from the default system package. Please to separate your custom build from the default system package. Please
replace ``LLVM_INSTALL_PATH`` with your own path. 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 **Note**: With LLVM 3.2, the default build configuration has C++ RTTI
disabled. However, llvmpy requires 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:: 4. Get llvm-py and install it::

View file

@ -4,8 +4,6 @@ import llvm
from llvm.core import Module from llvm.core import Module
from llvm.ee import EngineBuilder from llvm.ee import EngineBuilder
from llvm.utils import check_intrinsics
m = Module.new('fjoidajfa') m = Module.new('fjoidajfa')
eb = EngineBuilder.new(m) eb = EngineBuilder.new(m)
target = eb.select_target() target = eb.select_target()
@ -15,8 +13,7 @@ if sys.platform == 'darwin':
s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]]
assert target.triple.startswith(s + '-apple-darwin') assert target.triple.startswith(s + '-apple-darwin')
assert llvm.test(verbosity=2, run_isolated=False) == 0 assert llvm.test(verbosity=2) == 0
#check_intrinsics.main()
print('llvm.__version__: %s' % llvm.__version__) print('llvm.__version__: %s' % llvm.__version__)
#assert llvm.__version__ == '0.12.0' #assert llvm.__version__ == '0.12.0'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -3,8 +3,8 @@
You can adapt this file completely to your liking, but it should at least You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive. contain the root `toctree` directive.
llvmpy Documentation for llvmpy
====== ========================
Contents: Contents:
@ -22,7 +22,7 @@ Contents:
Indices and tables Indices and tables
------------------ ==================
* :ref:`genindex` * :ref:`genindex`
* :ref:`modindex` * :ref:`modindex`

View file

@ -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()

View file

@ -9,8 +9,6 @@ version = extra.get_llvm_version()
del extra del extra
class Wrapper(object): class Wrapper(object):
__slots__ = '__ptr'
def __init__(self, ptr): def __init__(self, ptr):
assert ptr assert ptr
self.__ptr = ptr self.__ptr = ptr
@ -34,14 +32,14 @@ def _extract_ptrs(objs):
class LLVMException(Exception): class LLVMException(Exception):
pass pass
def test(verbosity=3, run_isolated=True): def test(verbosity=1):
"""test(verbosity=1) -> TextTestResult """test(verbosity=1) -> TextTestResult
Run self-test, and return the number of failures + errors Run self-test, and return the number of failures + errors
""" """
from llvm.tests import run from llvm.tests import run
result = run(verbosity=verbosity, run_isolated=run_isolated) result = run(verbosity=verbosity)
errct = len(result.failures) + len(result.errors)
return len(result.failures) + len(result.errors)
return errct

195
llvm/abi.py Normal file
View file

@ -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 '<ArgInfo %s>' % ' '.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

View file

@ -41,7 +41,7 @@ import contextlib, weakref
import llvm import llvm
from llvm._intrinsic_ids import * from llvm._intrinsic_ids import *
from llvm.deprecated import deprecated
from llvmpy import api from llvmpy import api
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
@ -379,7 +379,6 @@ class Module(llvm.Wrapper):
module_obj = Module.new('my_module') module_obj = Module.new('my_module')
""" """
__slots__ = '__weakref__'
__cache = weakref.WeakValueDictionary() __cache = weakref.WeakValueDictionary()
def __new__(cls, ptr): def __new__(cls, ptr):
@ -452,12 +451,12 @@ class Module(llvm.Wrapper):
""" """
return str(self._ptr) return str(self._ptr)
def __hash__(self):
return id(self._ptr)
def __eq__(self, rhs): def __eq__(self, rhs):
assert isinstance(rhs, Module), type(rhs)
if isinstance(rhs, Module): if isinstance(rhs, Module):
return self._ptr == rhs._ptr return str(self) == str(rhs)
else:
return False
def __ne__(self, rhs): def __ne__(self, rhs):
return not (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: Use one of the static methods to create an instance. Example:
ty = Type.double() ty = Type.double()
""" """
__slots__ = '__name__'
_type_ = api.llvm.Type _type_ = api.llvm.Type
def __init__(self, ptr): def __init__(self, ptr):
@ -882,7 +880,6 @@ class Type(llvm.Wrapper):
class IntegerType(Type): class IntegerType(Type):
"""Represents an integer type.""" """Represents an integer type."""
__slots__ = ()
_type_ = api.llvm.IntegerType _type_ = api.llvm.IntegerType
@property @property
@ -892,7 +889,6 @@ class IntegerType(Type):
class FunctionType(Type): class FunctionType(Type):
"""Represents a function type.""" """Represents a function type."""
__slots__ = ()
_type_ = api.llvm.FunctionType _type_ = api.llvm.FunctionType
@property @property
@ -922,7 +918,6 @@ class FunctionType(Type):
class StructType(Type): class StructType(Type):
"""Represents a structure type.""" """Represents a structure type."""
_type_ = api.llvm.StructType _type_ = api.llvm.StructType
__slots__ = ()
@property @property
def element_count(self): def element_count(self):
@ -981,7 +976,6 @@ class StructType(Type):
class ArrayType(Type): class ArrayType(Type):
"""Represents an array type.""" """Represents an array type."""
_type_ = api.llvm.ArrayType _type_ = api.llvm.ArrayType
__slots__ = ()
@property @property
def element(self): def element(self):
@ -993,7 +987,6 @@ class ArrayType(Type):
class PointerType(Type): class PointerType(Type):
_type_ = api.llvm.PointerType _type_ = api.llvm.PointerType
__slots__ = ()
@property @property
def pointee(self): def pointee(self):
@ -1005,7 +998,6 @@ class PointerType(Type):
class VectorType(Type): class VectorType(Type):
_type_ = api.llvm.VectorType _type_ = api.llvm.VectorType
__slots__ = ()
@property @property
def element(self): def element(self):
@ -1017,7 +1009,6 @@ class VectorType(Type):
class Value(llvm.Wrapper): class Value(llvm.Wrapper):
_type_ = api.llvm.Value _type_ = api.llvm.Value
__slots__ = '__weakref__'
def __init__(self, builder, ptr): def __init__(self, builder, ptr):
assert builder is _ValueFactory assert builder is _ValueFactory
@ -1086,7 +1077,6 @@ class Value(llvm.Wrapper):
class User(Value): class User(Value):
_type_ = api.llvm.User _type_ = api.llvm.User
__slots__ = ()
@property @property
def operand_count(self): def operand_count(self):
@ -1101,7 +1091,6 @@ class User(Value):
class Constant(User): class Constant(User):
_type_ = api.llvm.Constant _type_ = api.llvm.Constant
__slots__ = ()
@staticmethod @staticmethod
def null(ty): def null(ty):
@ -1287,7 +1276,6 @@ class Constant(User):
class ConstantExpr(Constant): class ConstantExpr(Constant):
_type_ = api.llvm.ConstantExpr _type_ = api.llvm.ConstantExpr
__slots__ = ()
@property @property
def opcode(self): def opcode(self):
@ -1298,20 +1286,19 @@ class ConstantExpr(Constant):
return self._ptr.getOpcodeName() return self._ptr.getOpcodeName()
class ConstantAggregateZero(Constant): class ConstantAggregateZero(Constant):
__slots__ = () pass
class ConstantDataArray(Constant): class ConstantDataArray(Constant):
__slots__ = () pass
class ConstantDataVector(Constant): class ConstantDataVector(Constant):
__slots__ = () pass
class ConstantInt(Constant): class ConstantInt(Constant):
_type_ = api.llvm.ConstantInt _type_ = api.llvm.ConstantInt
__slots__ = ()
@property @property
def z_ext_value(self): def z_ext_value(self):
@ -1327,32 +1314,30 @@ class ConstantInt(Constant):
class ConstantFP(Constant): class ConstantFP(Constant):
__slots__ = () pass
class ConstantArray(Constant): class ConstantArray(Constant):
__slots__ = () pass
class ConstantStruct(Constant): class ConstantStruct(Constant):
__slots__ = () pass
class ConstantVector(Constant): class ConstantVector(Constant):
__slots__ = () pass
class ConstantPointerNull(Constant): class ConstantPointerNull(Constant):
__slots__ = () pass
class UndefValue(Constant): class UndefValue(Constant):
__slots__ = () pass
class GlobalValue(Constant): class GlobalValue(Constant):
_type_ = api.llvm.GlobalValue _type_ = api.llvm.GlobalValue
__slots__ = ()
def _get_linkage(self): def _get_linkage(self):
return self._ptr.getLinkage() return self._ptr.getLinkage()
@ -1398,7 +1383,6 @@ class GlobalValue(Constant):
class GlobalVariable(GlobalValue): class GlobalVariable(GlobalValue):
_type_ = api.llvm.GlobalVariable _type_ = api.llvm.GlobalVariable
__slots__ = ()
@staticmethod @staticmethod
def new(module, ty, name, addrspace=0): def new(module, ty, name, addrspace=0):
@ -1459,7 +1443,6 @@ class GlobalVariable(GlobalValue):
thread_local = property(_get_thread_local, _set_thread_local) thread_local = property(_get_thread_local, _set_thread_local)
class Argument(Value): class Argument(Value):
__slots__ = ()
_type_ = api.llvm.Argument _type_ = api.llvm.Argument
_valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS,
ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) ATTR_NO_CAPTURE, ATTR_STRUCT_RET])
@ -1560,7 +1543,6 @@ class Argument(Value):
return self._ptr.hasStructRetAttr() return self._ptr.hasStructRetAttr()
class Function(GlobalValue): class Function(GlobalValue):
__slots__ = ()
_type_ = api.llvm.Function _type_ = api.llvm.Function
@staticmethod @staticmethod
@ -1699,7 +1681,6 @@ class Function(GlobalValue):
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class InlineAsm(Value): class InlineAsm(Value):
__slots__ = ()
_type_ = api.llvm.InlineAsm _type_ = api.llvm.InlineAsm
@staticmethod @staticmethod
@ -1714,7 +1695,6 @@ class InlineAsm(Value):
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class MetaData(Value): class MetaData(Value):
__slots__ = ()
_type_ = api.llvm.MDNode _type_ = api.llvm.MDNode
@staticmethod @staticmethod
@ -1771,7 +1751,6 @@ class MetaDataString(Value):
class NamedMetaData(llvm.Wrapper): class NamedMetaData(llvm.Wrapper):
__slots__ = ()
@staticmethod @staticmethod
def get_or_insert(mod, name): def get_or_insert(mod, name):
@ -1801,7 +1780,6 @@ class NamedMetaData(llvm.Wrapper):
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class Instruction(User): class Instruction(User):
__slots__ = ()
_type_ = api.llvm.Instruction _type_ = api.llvm.Instruction
@property @property
@ -1883,7 +1861,6 @@ class Instruction(User):
class CallOrInvokeInstruction(Instruction): class CallOrInvokeInstruction(Instruction):
__slots__ = ()
_type_ = api.llvm.CallInst, api.llvm.InvokeInst _type_ = api.llvm.CallInst, api.llvm.InvokeInst
def _get_cc(self): def _get_cc(self):
@ -1939,7 +1916,6 @@ class CallOrInvokeInstruction(Instruction):
class PHINode(Instruction): class PHINode(Instruction):
__slots__ = ()
_type_ = api.llvm.PHINode _type_ = api.llvm.PHINode
@property @property
@ -1957,7 +1933,6 @@ class PHINode(Instruction):
class SwitchInstruction(Instruction): class SwitchInstruction(Instruction):
__slots__ = ()
_type_ = api.llvm.SwitchInst _type_ = api.llvm.SwitchInst
def add_case(self, const, bblk): def add_case(self, const, bblk):
@ -1965,7 +1940,6 @@ class SwitchInstruction(Instruction):
class CompareInstruction(Instruction): class CompareInstruction(Instruction):
__slots__ = ()
_type_ = api.llvm.CmpInst _type_ = api.llvm.CmpInst
@property @property
@ -1977,40 +1951,11 @@ class CompareInstruction(Instruction):
return FCMPEnum.get(n) 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 # Basic block
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
class BasicBlock(Value): class BasicBlock(Value):
__slots__ = ()
_type_ = api.llvm.BasicBlock _type_ = api.llvm.BasicBlock
def insert_before(self, name): def insert_before(self, name):
@ -2037,7 +1982,6 @@ class BasicBlock(Value):
class _ValueFactory(object): class _ValueFactory(object):
__slots__ = ()
cache = weakref.WeakValueDictionary() cache = weakref.WeakValueDictionary()
# value ID -> class map # value ID -> class map
@ -2066,8 +2010,7 @@ class _ValueFactory(object):
VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction,
VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction, VALUE_INSTRUCTION + OPCODE_SWITCH : SwitchInstruction,
VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction, VALUE_INSTRUCTION + OPCODE_ICMP : CompareInstruction,
VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction, VALUE_INSTRUCTION + OPCODE_FCMP : CompareInstruction
VALUE_INSTRUCTION + OPCODE_ALLOCA : AllocaInstruction,
} }
@classmethod @classmethod
@ -2114,7 +2057,6 @@ _atomic_orderings = {
} }
class Builder(llvm.Wrapper): class Builder(llvm.Wrapper):
__slots__ = ()
@staticmethod @staticmethod
def new(basic_block): def new(basic_block):
@ -2276,6 +2218,7 @@ class Builder(llvm.Wrapper):
# memory # memory
def malloc(self, ty, name=""): def malloc(self, ty, name=""):
context = api.llvm.getGlobalContext()
allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr)
ity = allocsz.getType() ity = allocsz.getType()
malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr,
@ -2289,6 +2232,7 @@ class Builder(llvm.Wrapper):
return _make_value(inst) return _make_value(inst)
def malloc_array(self, ty, size, name=""): def malloc_array(self, ty, size, name=""):
context = api.llvm.getGlobalContext()
allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr) allocsz = api.llvm.ConstantExpr.getSizeOf(ty._ptr)
ity = allocsz.getType() ity = allocsz.getType()
malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr, malloc = api.llvm.CallInst.CreateMalloc(self.basic_block._ptr,
@ -2301,13 +2245,12 @@ class Builder(llvm.Wrapper):
inst = self._ptr.Insert(malloc, name) inst = self._ptr.Insert(malloc, name)
return _make_value(inst) return _make_value(inst)
def alloca(self, ty, size=None, name=""): def alloca(self, ty, name=""):
sizeptr = size._ptr if size else None intty = Type.int()
return _make_value(self._ptr.CreateAlloca(ty._ptr, sizeptr, name)) return _make_value(self._ptr.CreateAlloca(ty._ptr, None, name))
@deprecated
def alloca_array(self, ty, size, name=""): 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): def free(self, ptr):
free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr) free = api.llvm.CallInst.CreateFree(ptr._ptr, self.basic_block._ptr)
@ -2394,20 +2337,15 @@ class Builder(llvm.Wrapper):
# misc # misc
def extract_value(self, retval, idx, name=""): def extract_value(self, retval, idx, name=""):
if not isinstance(idx, (tuple, list)): return _make_value(self._ptr.CreateExtractValue(retval._ptr, [idx], name))
idx = [idx]
return _make_value(self._ptr.CreateExtractValue(retval._ptr, idx,
name))
# obsolete synonym for extract_value # obsolete synonym for extract_value
getresult = extract_value getresult = extract_value
def insert_value(self, retval, rhs, idx, name=""): def insert_value(self, retval, rhs, idx, name=""):
if not isinstance(idx, (tuple, list)):
idx = [idx]
return _make_value(self._ptr.CreateInsertValue(retval._ptr, return _make_value(self._ptr.CreateInsertValue(retval._ptr,
rhs._ptr, rhs._ptr,
idx, [idx],
name)) name))
def phi(self, ty, name=""): def phi(self, ty, name=""):

View file

@ -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

View file

@ -238,27 +238,3 @@ def dylib_add_symbol(name, ptr):
def dylib_address_of_symbol(name): def dylib_address_of_symbol(name):
return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(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)

View file

@ -80,15 +80,6 @@ class PassManagerBuilder(llvm.Wrapper):
self._ptr.BBVectorize = enable self._ptr.BBVectorize = enable
vectorize = bbvectorize vectorize = bbvectorize
@property
def slpvectorize(self):
return self._ptr.SLPVectorize
@slpvectorize.setter
def slpvectorize(self, enable):
self._ptr.SLPVectorize = enable
else: else:
@property @property
def vectorize(self): def vectorize(self):
@ -320,15 +311,13 @@ class TargetTransformInfo(Pass):
# Helpers # Helpers
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False, def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False,
slp_vectorize=False, vectorize=False, inline_threshold=2000, pm=True, fpm=True, mod=None):
inline_threshold=None, pm=True, fpm=True, mod=None):
''' '''
tm --- The TargetMachine for which the passes are optimizing for. tm --- The TargetMachine for which the passes are optimizing for.
The TargetMachine must stay alive until the pass managers The TargetMachine must stay alive until the pass managers
are removed. are removed.
opt --- [0-3] Optimization level. Default to 2. 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. loop_vectorize --- [boolean] Whether to use loop-vectorizer.
vectorize --- [boolean] Whether to use basic-block vectorizer. vectorize --- [boolean] Whether to use basic-block vectorizer.
inline_threshold --- [int] Threshold for the inliner. 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. fpm --- [boolean] Whether to build a function-level pass-manager.
mod --- [Module] The module object for the FunctionPassManager. 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: if pm:
pm = PassManager.new() pm = PassManager.new()
if fpm: if fpm:
@ -361,27 +338,22 @@ def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False,
pmb.opt_level = opt pmb.opt_level = opt
pmb.vectorize = vectorize pmb.vectorize = vectorize
pmb.loop_vectorize = loop_vectorize pmb.loop_vectorize = loop_vectorize
if llvm.version >= (3, 3):
pmb.slp_vectorize = slp_vectorize
if inline_threshold: if inline_threshold:
pmb.use_inliner_with_threshold(inline_threshold) pmb.use_inliner_with_threshold(inline_threshold)
if pm: if pm:
pm.add(tm.target_data.clone()) pm.add(tm.target_data.clone())
pm.add(TargetLibraryInfo.new(tm.triple)) pm.add(TargetLibraryInfo.new(tm.triple))
if llvm.version <= (3, 2): if llvm.version == (3, 2):
pm.add(TargetTransformInfo.new(tm)) pm.add(TargetTransformInfo.new(tm))
else:
tm.add_analysis_passes(pm)
pmb.populate(pm) pmb.populate(pm)
if fpm: if fpm:
fpm.add(tm.target_data.clone()) fpm.add(tm.target_data.clone())
fpm.add(TargetLibraryInfo.new(tm.triple)) fpm.add(TargetLibraryInfo.new(tm.triple))
if llvm.version <= (3, 2): if llvm.version == (3, 2):
fpm.add(TargetTransformInfo.new(tm)) fpm.add(TargetTransformInfo.new(tm))
else:
tm.add_analysis_passes(fpm)
pmb.populate(fpm) pmb.populate(fpm)
fpm.initialize()
from collections import namedtuple from collections import namedtuple
return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm)

View file

@ -191,10 +191,6 @@ class TargetMachine(llvm.Wrapper):
def target(self): def target(self):
return self._ptr.getTarget() 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): if llvm.version >= (3, 4):
@property @property
def reg_info(self): def reg_info(self):

View file

@ -12,7 +12,7 @@ tests = [] # stores unittest.TestCase objects
isolated_tests = [] # stores modue name 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 is installed in: ' + os.path.dirname(__file__))
print('llvmpy version: ' + llvm.__version__) print('llvmpy version: ' + llvm.__version__)
print(sys.version) print(sys.version)
@ -37,32 +37,23 @@ def run(verbosity=1, run_isolated=True):
if sys.version_info[:2] > (2, 6): if sys.version_info[:2] > (2, 6):
kwargs['buffer'] = True kwargs['buffer'] = True
runner = unittest.TextTestRunner(**kwargs) runner = unittest.TextTestRunner(**kwargs)
testresult = runner.run(suite)
try: if testresult:
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:
# Run isolated tests # Run isolated tests
print("run isolated tests".center(80, '-')) print("run isolated tests".center(80, '-'))
for test in isolated_tests: for test in isolated_tests:
print(('testing %s' % test).center(80)) print(('testing %s' % test).center(80))
cmd = [sys.executable, '-m', test] cmd = [sys.executable, '-m', test]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
for line in p.stdout: for line in p.stdout:
print(line.decode('utf8'), end='') print(line, end='')
p.wait() p.wait()
if p.returncode: if p.returncode:
raise Exception("%s returned: %d" % (test, p.returncode)) raise Exception("%s returned: %d" % p.returncode)
return testresult return testresult

28
llvm/tests/test_abi.py Normal file
View file

@ -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()

View file

@ -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()

View file

@ -6,9 +6,8 @@ import subprocess
import tempfile import tempfile
from distutils.spawn import find_executable from distutils.spawn import find_executable
from llvm.core import (Module, Type, Builder, Constant) 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): class TestNative(TestCase):
def setUp(self): def setUp(self):
@ -61,10 +60,10 @@ class TestNative(TestCase):
self._compile(src) self._compile(src)
def test_object(self): def test_object(self):
''' # if sys.platform == 'darwin':
Note: Older Darwin with GCC will report missing _main symbol when # # skip this test on MacOSX for now
compile the object file to an executable. # return
'''
m = self._make_module() m = self._make_module()
output = m.to_native_object() output = m.to_native_object()
@ -74,7 +73,8 @@ class TestNative(TestCase):
self._compile(src) self._compile(src)
tests.append(TestNative) if sys.platform != 'win32':
tests.append(TestNative)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View file

@ -1,5 +1,5 @@
import unittest import unittest
from llvm.core import Type, Module, Builder, Constant from llvm.core import Type
from .support import TestCase, tests from .support import TestCase, tests
class TestStruct(TestCase): class TestStruct(TestCase):
@ -8,19 +8,6 @@ class TestStruct(TestCase):
tb = Type.struct([Type.int(32), Type.float()]) tb = Type.struct([Type.int(32), Type.float()])
self.assertTrue(ta.is_layout_identical(tb)) 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) tests.append(TestStruct)
if __name__ == '__main__': if __name__ == '__main__':

View file

View file

@ -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:])

View file

@ -12,11 +12,7 @@ http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf
""" """
import sys import sys, os, subprocess
import os
import subprocess
import contextlib
def detect_avx_support(option='detect'): def detect_avx_support(option='detect'):
'''Detect AVX support''' '''Detect AVX support'''
@ -40,25 +36,13 @@ def detect_unix_like():
except IOError: except IOError:
return False return False
with contextlib.closing(info): for line in info:
for line in info: if line.lstrip().startswith('flags'):
if line.lstrip().startswith('flags'): features = line.split()
features = line.split() if 'avx' in features and 'xsave' in features:
if 'avx' in features and 'xsave' in features: # enable AVX if flags contain AVX
# enable AVX if flags contain AVX return True
return True return False
return False
@contextlib.contextmanager
def _close_popen(popen):
if sys.version_info[0] >= 3:
with popen:
yield
else:
yield
popen.stdout.close()
def detect_osx_like(): def detect_osx_like():
try: try:
@ -66,11 +50,9 @@ def detect_osx_like():
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
except OSError: except OSError:
return False return False
features = info.stdout.read().decode('UTF8')
with _close_popen(info): features = features.split()
features = info.stdout.read().decode('UTF8') return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features
features = features.split()
return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -349,7 +349,7 @@ class CBuilder(object):
elif not isinstance(count, lc.Value): elif not isinstance(count, lc.Value):
count = self.constant(types.int, count).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) return CArray(self, ptr)
def ret(self, val=None): def ret(self, val=None):

View file

@ -1,95 +1,55 @@
#include <Python.h> #include <Python.h>
#include <structmember.h>
#include <python3adapt.h> #include <python3adapt.h>
#include <capsulethunk.h> #include <capsulethunk.h>
#include <llvm_binding/capsule_context.h> #include <llvm_binding/capsule_context.h>
#include <llvm_binding/auto_pyobject.h>
#include <string>
#include <sstream>
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 static
PyObject* GetAPIModule(){ PyObject* getName(PyObject* self, PyObject* args) {
if (NULL == TheAPIModule) PyObject* obj;
TheAPIModule = PyImport_ImportModule("llvmpy._api"); if (!PyArg_ParseTuple(args, "O", &obj)){
return TheAPIModule; return NULL;
}
const char* name = PyCapsule_GetName(obj);
if (!name) return NULL;
return PyString_FromString(name);
} }
static static
PyObject* GetCapsuleModule(){ PyObject* getPointer(PyObject* self, PyObject* args) {
if (NULL == TheCapsuleModule) PyObject* obj;
TheCapsuleModule = PyImport_ImportModule("llvmpy.capsule"); if (!PyArg_ParseTuple(args, "O", &obj)){
return TheCapsuleModule; return NULL;
}
void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj));
if (!pointer) return NULL;
return PyLong_FromVoidPtr(pointer);
} }
static static
PyObject* GetCapsuleClass() { PyObject* check(PyObject* self, PyObject* args) {
if (NULL == TheCapsuleClass) PyObject* obj;
TheCapsuleClass = PyObject_GetAttrString(GetCapsuleModule(), if (!PyArg_ParseTuple(args, "O", &obj)){
"Capsule"); return NULL;
return TheCapsuleClass; }
if (PyCapsule_CheckExact(obj)) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
} }
static // ------------------
PyObject* GetWrapperClass() { // PyCapsule Context
if (NULL == TheWrapperClass) // ------------------
TheWrapperClass = PyObject_GetAttrString(GetCapsuleModule(),
"Wrapper");
return TheWrapperClass;
}
static static
PyObject* GetCache() { CapsuleContext* getContext(PyObject* self, PyObject* args) {
if (NULL == TheCache) PyObject* obj;
TheCache = PyObject_GetAttrString(GetCapsuleModule(), "_cache"); if (!PyArg_ParseTuple(args, "O", &obj)) {
return TheCache; return NULL;
} }
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) {
void* context = PyCapsule_GetContext(obj); void* context = PyCapsule_GetContext(obj);
if (!context) { if (!context) {
PyErr_SetString(PyExc_TypeError, "PyCapsule has no context."); PyErr_SetString(PyExc_TypeError, "PyCapsule has no context.");
@ -99,8 +59,9 @@ CapsuleContext* GetContext(PyObject *obj) {
} }
static static
PyObject* GetClassName(PyObject* obj) { PyObject* getClassName(PyObject* self, PyObject* args) {
CapsuleContext* context = GetContext(obj); CapsuleContext* context = getContext(self, args);
//Assert(context->_magic == 0xdead);
if (!context) { if (!context) {
return NULL; return NULL;
} else { } 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 <sizeof(pointer); ++i) {
hash ^= ((unsigned char*)&pointer)[i];
hash = RotR(hash, 11);
}
return hash;
}
static
bool Capsule_eq(PyObject *self, PyObject *other) {
if (PyObject_Type(self) == PyObject_Type(other)) {
CapsuleObject *a = (CapsuleObject*)self;
CapsuleObject *b = (CapsuleObject*)other;
void* pa = PyCapsule_GetPointer(a->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[] = { static PyMethodDef core_methods[] = {
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } #define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
@ -585,10 +76,6 @@ static PyMethodDef core_methods[] = {
declmethod(getPointer), declmethod(getPointer),
declmethod(check), declmethod(check),
declmethod(getClassName), declmethod(getClassName),
declmethod(unwrap),
declmethod(wrap),
declmethod(has_ownership),
declmethod(downcast),
{ NULL }, { NULL },
#undef declmethod #undef declmethod
}; };
@ -619,21 +106,10 @@ extern "C" {
#else #else
PyObject *module = Py_InitModule("_capsule", core_methods); PyObject *module = Py_InitModule("_capsule", core_methods);
#endif #endif
if (module == NULL){ if (module == NULL)
INITERROR; 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 #if PY_MAJOR_VERSION >= 3
return module; return module;
#endif #endif
} }

View file

@ -1,27 +1,19 @@
from weakref import WeakValueDictionary from weakref import WeakKeyDictionary, WeakValueDictionary, ref
from collections import defaultdict from collections import defaultdict
import logging import logging
from llvmpy._capsule import (unwrap, has_ownership, downcast, wrap,
getClassName, getName, getPointer, Capsule)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
NO_DEBUG = False NO_DEBUG = False
def silent_logger(): def silent_logger():
''' '''
Silent logger for unless we have a error message. Silent logger for unless we have a error message.
''' '''
global NO_DEBUG
logger.setLevel(logging.ERROR) logger.setLevel(logging.ERROR)
NO_DEBUG = True NO_DEBUG = True
# comment out the line below to re-enable logging at DEBUG level. # comment out the line below to re-enable logging at DEBUG level.
silent_logger() silent_logger()
def set_debug(enabled): def set_debug(enabled):
''' '''
Side-effect: configure logger with it is not configured. Side-effect: configure logger with it is not configured.
@ -36,63 +28,79 @@ def set_debug(enabled):
else: else:
logger.setLevel(logging.WARNING) 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): class Capsule(object):
# "Wraps PyCapsule so that we can build weakref of it." "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)
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) _addr2refct = defaultdict(lambda: 0)
#_capsule2weak = WeakKeyDictionary() _capsule2weak = WeakKeyDictionary()
_addr2dtor = {} _addr2dtor = {}
_pyclasses = {} _pyclasses = {}
@ -100,16 +108,15 @@ _pyclasses = {}
# NOTE: The same 'addr' may appear in multiple class bins. # NOTE: The same 'addr' may appear in multiple class bins.
_cache = defaultdict(WeakValueDictionary) _cache = defaultdict(WeakValueDictionary)
def release_ownership(old): def release_ownership(old):
logger.debug('Release %s', old) logger.debug('Release %s', old)
addr = getPointer(old) addr = Capsule.getPointer(old)
name = getName(old) name = Capsule.getName(old)
if _addr2dtor.get((name, addr)) is None: if _addr2dtor.get((name, addr)) is None:
clsname = getClassName(old) clsname = Capsule.getClassName(old)
if not _pyclasses[clsname]._has_dtor(): if not _pyclasses[clsname]._has_dtor():
return return
# Guard duplicated release # Guard duplicated release
raise Exception("Already released") raise Exception("Already released")
_addr2dtor[(name, addr)] = None _addr2dtor[(name, addr)] = None
@ -119,86 +126,61 @@ def obtain_ownership(cap):
if cls._has_dtor(): if cls._has_dtor():
addr = cap.pointer addr = cap.pointer
name = cap.name name = cap.name
assert _addr2dtor[(name, addr)] is None assert _addr2dtor[addr] is None
_addr2dtor[(name, addr)] = cls._delete_ _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): def wrap(cap, owned=False):
# addr = Capsule.getPointer(cap) '''Wrap a PyCapsule with the corresponding Wrapper class.
# name = Capsule.getName(cap) If `cap` is not a PyCapsule, returns `cap`
# return _addr2dtor.get((name, addr)) is not None '''
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): def unwrap(obj):
# '''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):
'''Unwrap a Wrapper instance into the underlying PyCapsule. '''Unwrap a Wrapper instance into the underlying PyCapsule.
If `obj` is not a Wrapper instance, returns `obj`. If `obj` is not a Wrapper instance, returns `obj`.
''' '''
# if isinstance(obj, Wrapper): if isinstance(obj, Wrapper):
# return obj._ptr return obj._ptr
# else: else:
# return obj return obj
def register_class(clsname): def register_class(clsname):
def _wrapped(cls): def _wrapped(cls):
_pyclasses[clsname] = cls _pyclasses[clsname] = cls
return cls return cls
return _wrapped return _wrapped
class Wrapper(object): class Wrapper(object):
__slots__ = '__capsule' __slots__ = '__capsule'
def __init__(self, capsule): def __init__(self, capsule):
self.__capsule = 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 @property
def _capsule(self): def _capsule(self):
return self.__capsule return self.__capsule
@ -211,11 +193,10 @@ class Wrapper(object):
return hash(self._capsule) return hash(self._capsule)
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, Wrapper): return self._capsule == other._capsule
return self._capsule == other._capsule
def __ne__(self, other): def __ne__(self, other):
return not (self == other) return not(self == other)
def _downcast(self, newcls): def _downcast(self, newcls):
return downcast(self, newcls) return downcast(self, newcls)
@ -224,25 +205,24 @@ class Wrapper(object):
def _has_dtor(cls): def _has_dtor(cls):
return hasattr(cls, '_delete_') 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

View file

@ -1,4 +1,5 @@
import inspect, textwrap import inspect, textwrap
import functools
import codegen as cg import codegen as cg
import os import os
@ -7,12 +8,10 @@ namespaces = {}
RESERVED = frozenset(['None']) RESERVED = frozenset(['None'])
def makedir(directory): def makedir(directory):
if not os.path.exists(directory): if not os.path.exists(directory):
os.makedirs(directory) os.makedirs(directory)
class SubModule(object): class SubModule(object):
def __init__(self): def __init__(self):
self.methods = [] self.methods = []
@ -294,10 +293,6 @@ class Class(SubModule, _Type):
writer.println('@capsule.register_class("%s")' % self.fullname) writer.println('@capsule.register_class("%s")' % self.fullname)
with writer.block('class %(clsname)s(%(bases)s):' % locals()): with writer.block('class %(clsname)s(%(bases)s):' % locals()):
writer.println('_llvm_type_ = "%s"' % self.fullname) writer.println('_llvm_type_ = "%s"' % self.fullname)
if self.bases:
writer.println('__slots__ = ()')
else:
writer.println('__slots__ = "__weakref__"')
for enum in self.enums: for enum in self.enums:
enum.compile_py(writer) enum.compile_py(writer)
for meth in self.methods: for meth in self.methods:
@ -404,7 +399,6 @@ class Enum(object):
writer.println(fmt % locals()) writer.println(fmt % locals())
writer.println() writer.println()
class Method(object): class Method(object):
_kind_ = 'meth' _kind_ = 'meth'
@ -522,7 +516,6 @@ class Method(object):
with writer.block('if len(%s) > %d:' % (unwrapped, i)): with writer.block('if len(%s) > %d:' % (unwrapped, i)):
writer.release_ownership('%s[%d]' % (unwrapped, i)) writer.release_ownership('%s[%d]' % (unwrapped, i))
class CustomMethod(Method): class CustomMethod(Method):
def __init__(self, methodname, retty, *argtys): def __init__(self, methodname, retty, *argtys):
super(CustomMethod, self).__init__(retty, *argtys) super(CustomMethod, self).__init__(retty, *argtys)
@ -601,7 +594,6 @@ class CustomFunction(Function):
def fullname(self): def fullname(self):
return self.realname return self.realname
class Destructor(Method): class Destructor(Method):
_kind_ = 'dtor' _kind_ = 'dtor'
@ -633,7 +625,6 @@ class Constructor(StaticMethod):
ret = writer.declare(retty.fullname, stmt) ret = writer.declare(retty.fullname, stmt)
return ret return ret
class ref(_Type): class ref(_Type):
def __init__(self, element): def __init__(self, element):
assert isinstance(element, Class), type(element) assert isinstance(element, Class), type(element)
@ -695,16 +686,13 @@ class ptr(_Type):
return writer.pycapsule_new(val, self.element.capsule_name, return writer.pycapsule_new(val, self.element.capsule_name,
self.element.fullname) self.element.fullname)
class ownedptr(ptr): class ownedptr(ptr):
pass pass
def const(ptr_or_ref): def const(ptr_or_ref):
ptr_or_ref.const = True ptr_or_ref.const = True
return ptr_or_ref return ptr_or_ref
class cast(_Type): class cast(_Type):
format = 'O' format = 'O'
@ -769,7 +757,6 @@ class CustomPythonMethod(object):
for line in self.sourcelines: for line in self.sourcelines:
writer.println(line) writer.println(line)
class CustomPythonStaticMethod(CustomPythonMethod): class CustomPythonStaticMethod(CustomPythonMethod):
def compile_py(self, writer): def compile_py(self, writer):
writer.println('@staticmethod') writer.println('@staticmethod')
@ -858,7 +845,6 @@ class Attr(object):
TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split() TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split()
def _parse_llvm_version(ver): def _parse_llvm_version(ver):
import re import re
m = re.compile(r'(\d+)\.(\d+)').match(ver) m = re.compile(r'(\d+)\.(\d+)').match(ver)

View file

@ -9,7 +9,7 @@ extern "C" {
#if (PY_MAJOR_VERSION >= 3) #if (PY_MAJOR_VERSION >= 3)
PyMODINIT_FUNC PyObject *
PyInit_%(module)s(void) PyInit_%(module)s(void)
{ {
PyObject *module = create_python_module("%(module)s", meth_%(ns)s); PyObject *module = create_python_module("%(module)s", meth_%(ns)s);

View file

@ -40,7 +40,7 @@
namespace extra{ namespace extra{
using namespace llvm; using namespace llvm;
class raw_svector_ostream_helper: public raw_svector_ostream { class raw_svector_ostream_helper: public raw_svector_ostream {
SmallVectorImpl<char> *SV; SmallVectorImpl<char> *SV;
public: public:
@ -85,7 +85,7 @@ PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args)
{ {
using extra::raw_svector_ostream_helper; using extra::raw_svector_ostream_helper;
using llvm::raw_svector_ostream; using llvm::raw_svector_ostream;
if (!PyArg_ParseTuple(args, "")) { if (!PyArg_ParseTuple(args, "")) {
return NULL; return NULL;
} }
@ -99,7 +99,7 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args)
{ {
using llvm::Type; using llvm::Type;
typedef llvm::SmallVector<llvm::Type*, 8> SmallVector_Type; typedef llvm::SmallVector<llvm::Type*, 8> SmallVector_Type;
SmallVector_Type* SV = new SmallVector_Type; SmallVector_Type* SV = new SmallVector_Type;
Py_ssize_t size = PyTuple_Size(args); Py_ssize_t size = PyTuple_Size(args);
for (Py_ssize_t i = 0; i < size; ++i) { 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); PyObject* list = PyList_New(0);
for(; begin != end; ++begin) { for(; begin != end; ++begin) {
auto_pyobject cap = pycapsule_new(&*begin, capsuleName, className); PyObject* cap = pycapsule_new(&*begin, capsuleName, className);
PyList_Append(list, *cap); PyList_Append(list, cap);
} }
return list; return list;
} }
@ -198,8 +198,8 @@ PyObject* iterator_to_pylist(iterator begin, iterator end,
{ {
PyObject* list = PyList_New(0); PyObject* list = PyList_New(0);
for(; begin != end; ++begin) { for(; begin != end; ++begin) {
auto_pyobject cap = pycapsule_new(*begin, capsuleName, className); PyObject* cap = pycapsule_new(*begin, capsuleName, className);
PyList_Append(list, *cap); PyList_Append(list, cap);
} }
return list; return list;
} }
@ -420,7 +420,7 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE,
PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?"); PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?");
return NULL; return NULL;
} }
GenericValue* gv = static_cast<GenericValue*>( GenericValue* gv = static_cast<GenericValue*>(
PyCapsule_GetPointer(obj, GVN)); PyCapsule_GetPointer(obj, GVN));
@ -575,11 +575,11 @@ PyObject* TargetMachine_addPassesToEmitFile(
bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify); bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify);
if (status) { if (status) {
StringRef sr = rso.str(); StringRef sr = rso.str();
auto_pyobject buf = PyString_FromStringAndSize(sr.data(), sr.size()); PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size());
if (!buf) { if (!buf) {
return NULL; return NULL;
} }
if (-1 == PyFile_WriteObject(*buf, Out, Py_PRINT_RAW)){ if (-1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW)){
return NULL; return NULL;
} }
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -626,7 +626,7 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker,
if (! failed) { if (! failed) {
Py_RETURN_FALSE; Py_RETURN_FALSE;
} else { } else {
auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
if (NULL == callwrite(ErrMsg, *buf)){ if (NULL == callwrite(ErrMsg, *buf)){
return NULL; 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{ class PassRegistryEnumerator : public llvm::PassRegistrationListener{
public: public:
PyObject* List; PyObject* List;
@ -891,8 +870,7 @@ public:
inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ inline virtual void passEnumerate(const llvm::PassInfo * pass_info){
PyObject* passArg = PyString_FromString(pass_info->getPassArgument()); PyObject* passArg = PyString_FromString(pass_info->getPassArgument());
PyObject* passName = PyString_FromString(pass_info->getPassName()); PyObject* passName = PyString_FromString(pass_info->getPassName());
auto_pyobject pair = Py_BuildValue("(OO)", passArg, passName); PyList_Append(List, Py_BuildValue("(OO)", passArg, passName));
PyList_Append(List, *pair);
} }
}; };
@ -1010,7 +988,7 @@ fail:
} }
static static
PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm, PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
llvm::MCInst &instr, llvm::MCInst &instr,
const llvm::MemoryObject &region, const llvm::MemoryObject &region,
uint64_t address uint64_t address
@ -1020,7 +998,7 @@ PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
llvm::MCDisassembler::DecodeStatus status; llvm::MCDisassembler::DecodeStatus status;
size = 0; size = 0;
status = disasm->getInstruction(instr, size, region, address, status = disasm->getInstruction(instr, size, region, address,
llvm::nulls(), llvm::nulls()); llvm::nulls(), llvm::nulls());
return Py_BuildValue("(i,i)", int(status), size); return Py_BuildValue("(i,i)", int(status), size);
} }
@ -1068,5 +1046,5 @@ PyObject* llvm_sys_isBigEndianHost()
else else
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
#endif #endif

View file

@ -1,13 +1,12 @@
from binding import * from binding import *
from .namespace import llvm from .namespace import llvm
from .Value import Function, BasicBlock, Value from .Value import Function, BasicBlock
from .Instruction import Instruction, TerminatorInst from .Instruction import Instruction, TerminatorInst
from .LLVMContext import LLVMContext from .LLVMContext import LLVMContext
from .ADT.StringRef import StringRef from .ADT.StringRef import StringRef
@BasicBlock @BasicBlock
class BasicBlock: class BasicBlock:
_downcast_ = Value
Create = StaticMethod(ptr(BasicBlock), ref(LLVMContext), Create = StaticMethod(ptr(BasicBlock), ref(LLVMContext),
cast(str, StringRef), cast(str, StringRef),
ptr(Function), ptr(Function),

View file

@ -346,9 +346,6 @@ class AllocaInst:
isStaticAlloca = Method(cast(Bool, bool)) isStaticAlloca = Method(cast(Bool, bool))
getArraySize = Method(ptr(Value)) getArraySize = Method(ptr(Value))
getAllocatedType = Method(ptr(Type)) getAllocatedType = Method(ptr(Type))
getAlignment = Method(cast(Unsigned, int))
setAlignment = Method(Void, cast(int, Unsigned))
getArraySize = Method(ptr(Value))
@CastInst @CastInst

View file

@ -26,10 +26,3 @@ class DynamicLibrary:
cast(str, StringRef), # symbolName cast(str, StringRef), # symbolName
cast(int, VoidPtr), # address cast(int, VoidPtr), # address
) )
getPermanentLibrary = CustomStaticMethod(
'DynamicLibrary_getPermanentLibrary',
PyObjectPtr,
cast(str, ConstCharPtr), # filename
PyObjectPtr, # std::string * errmsg = 0
).require_only(1)

View file

@ -53,9 +53,6 @@ class TargetMachine:
getVectorTargetTransformInfo = Method(const( getVectorTargetTransformInfo = Method(const(
ownedptr(VectorTargetTransformInfo))) ownedptr(VectorTargetTransformInfo)))
else:
addAnalysisPasses = Method(Void, ref(PassManagerBase))
addPassesToEmitFile = Method(cast(bool, Bool), addPassesToEmitFile = Method(cast(bool, Bool),
ref(PassManagerBase), ref(PassManagerBase),
ref(formatted_raw_ostream), ref(formatted_raw_ostream),

View file

@ -189,8 +189,7 @@ setup(
'llpython', 'llpython',
'llvm_array', 'llvm_array',
'llvmpy.api', 'llvmpy.api.llvm', 'llvmpy.api', 'llvmpy.api.llvm',
'llvm.tests', 'llvm.tests',],
'llvm.utils',],
package_data = {'llvm': ['llrt/*.ll']}, package_data = {'llvm': ['llrt/*.ll']},
py_modules = ['llvmpy', py_modules = ['llvmpy',
'llvmpy._capsule', 'llvmpy._capsule',

View file

@ -3,7 +3,7 @@
# Import the llvm-py modules. # Import the llvm-py modules.
from llvm import * from llvm import *
from llvm.core import * from llvm.core import *
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
import logging import logging
import unittest import unittest

View file

@ -2,7 +2,7 @@ from llvm.core import *
from llvm.passes import * from llvm.passes import *
from llvm.ee import * from llvm.ee import *
import llvm import llvm
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
from os.path import dirname, join as join_path from os.path import dirname, join as join_path

View file

@ -1,7 +1,7 @@
from __future__ import print_function from __future__ import print_function
import unittest import unittest
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
from llvm.core import * from llvm.core import *
class TestMetaData(TestCase): class TestMetaData(TestCase):

View file

@ -1,6 +1,6 @@
from llvm.core import * from llvm.core import *
from llvm.tbaa import * from llvm.tbaa import *
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
import unittest import unittest
class TestTBAABuilder(TestCase): class TestTBAABuilder(TestCase):

View file

@ -7,7 +7,7 @@ import unittest, sys, logging
from llvm import * from llvm import *
from llvm.core import * from llvm.core import *
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
class TestModule(TestCase): class TestModule(TestCase):

View file

@ -4,7 +4,7 @@ import unittest
import llvm.ee import llvm.ee
from llvm.core import * from llvm.core import *
from llvm import _dwarf, debuginfo from llvm import _dwarf, debuginfo
from llvm.tests.support import TestCase from llvm.test_llvmpy import TestCase
class TestDebugInfo(TestCase): class TestDebugInfo(TestCase):