Compare commits

..

39 commits

Author SHA1 Message Date
Siu Kwan Lam
34900d2748 Update README.rst 2014-04-29 13:25:43 -05:00
Siu Kwan Lam
749b518b90 Update changelog 2014-04-28 11:06:48 -05:00
Siu Kwan Lam
c07fce0477 Update MANIFEST.in (#99) 2014-04-28 11:03:13 -05:00
Siu Kwan Lam
7f8476dd33 Fixing leaks (#92); thanks to ksshelt and eltjpm. 2014-04-04 15:14:47 -05:00
Siu Kwan Lam
57afefb069 Update change log 2014-03-20 15:00:11 -05:00
Siu Kwan Lam
0629ccb226 Allow BasicBlock downcast to Value 2014-03-19 11:33:01 -05:00
Siu Kwan Lam
6e4620edc6 Disable check_intrinsic 2014-03-13 13:47:09 -05:00
Siu Kwan Lam
2410267c8e Disable isolated test in conda build 2014-03-13 13:20:08 -05:00
Siu Kwan Lam
bc12aae8c1 Hashable Module and fix Module __eq__ 2014-03-11 15:17:06 -05:00
Siu Kwan Lam
6578412437 Add binding for dynamic library loading 2014-03-06 11:58:40 -06:00
Siu Kwan Lam
ce696c9b4e Update changelog 2014-02-18 14:30:39 -06:00
Siu Kwan Lam
3befa1be59 Merge pull request #94 from cgohlke/patch-1
Fix ImportError for C extensions on Python 3.4b2
2014-02-18 14:27:32 -06:00
Siu Kwan Lam
a9174f09c5 Merge pull request #88 from cantora/tests-import-TestCase
Fix broken tests from test refactor
2014-02-18 14:20:39 -06:00
Siu Kwan Lam
b86cc097d9 Fix deprecated function use 2014-02-18 14:13:40 -06:00
Jay Bourque
0e9f434ad8 Fix release date year in CHANGELOG 2014-02-10 10:54:08 -06:00
cgohlke
e868b825bb Fix ImportError of C extensions on Python 3.4b2 2014-02-04 15:52:41 -08:00
Ilan Schnell
dd2a569d76 fix release date 2014-02-04 14:22:53 -06:00
Siu Kwan Lam
059192f1ae Update change log 2014-01-31 17:33:32 -06:00
Siu Kwan Lam
3db6d8352a Fix isolated test runner 2014-01-16 18:34:19 -06:00
Siu Kwan Lam
00db78d89e Edit conda buildscript 2014-01-16 17:45:15 -06:00
Siu Kwan Lam
d9eb3ec175 Update setup.py 2014-01-16 17:11:21 -06:00
Siu Kwan Lam
4ed8f80774 Fix avx_support; only run check_intrinsics for conda build test 2014-01-16 17:03:40 -06:00
Siu Kwan Lam
43095609c3 Add intrinsic check 2014-01-16 16:49:23 -06:00
Siu Kwan Lam
b9cccbf9ae Close everything properly 2014-01-16 11:22:52 -06:00
Siu Kwan Lam
8689d62f02 Fix for PY3 2014-01-15 17:41:15 -06:00
Siu Kwan Lam
17d3cef4bd Fix build_pass_manager fpm handling 2013-12-31 16:57:45 -06:00
Siu Kwan Lam
ecac668bef Fix inline threshold and add size level 2013-12-27 22:21:33 -06:00
Siu Kwan Lam
078f1fe5c1 Move capsule code into C++ 2013-12-23 17:17:12 -06:00
Siu Kwan Lam
b9752e1e98 Add deprecated module and deprecate alloca_array 2013-12-20 12:26:35 -06:00
Siu Kwan Lam
f8c1c78df1 Leaner 2013-12-18 15:25:14 -06:00
Siu Kwan Lam
b8e0338da8 Add AllocaInstruction 2013-12-18 10:43:11 -06:00
Siu Kwan Lam
091a393d1d insert_value, extract_value can be multiple dimensional 2013-12-16 14:05:19 -06:00
anthony cantor
d7590fb029 change module name from llvm.test_llvmpy to llvm.tests.support
this seems to have been forgotten when test stuff was refactored.
2013-12-03 02:37:47 -07:00
Troy Powell
c199881b67 fixing index.rst 2013-11-18 15:59:01 -06:00
Ilan Schnell
fb3b6a3674 update changelog 2013-11-11 15:22:39 -06:00
Siu Kwan Lam
4e814b7d53 skip test for building executable from native object and assembly on OSX 2013-11-11 12:20:43 -06:00
Siu Kwan Lam
8a6dd7af7f fix loop-vectorize for llvm-3.3 2013-11-05 16:58:20 -06:00
Siu Kwan Lam
d08095299e add example for using vector instructions 2013-11-01 16:58:49 -05:00
Siu Kwan Lam
bf5859be7e fix bad version checking which disables auto-vectorization for llvm 3.3 2013-11-01 16:50:53 -05:00
42 changed files with 1438 additions and 553 deletions

View file

@ -1,5 +1,35 @@
2013-8-28 0.12.0:
--------------------
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:
---------------------
* 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)

View file

@ -1,5 +1,6 @@
include CHANGELOG LICENSE README setup.py MANIFEST.in
include CHANGELOG LICENSE README.rst setup.py MANIFEST.in versioneer.py
recursive-include llvm *
recursive-include llvmpy *
recursive-include www *
recursive-include test *
recursive-include tools *

View file

@ -30,10 +30,13 @@ 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`` to build.
3. Run ``REQUIRES_RTTI=1 make install`` to build and install.
**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::

View file

@ -4,6 +4,8 @@ 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()
@ -13,7 +15,8 @@ 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
assert llvm.test(verbosity=2, run_isolated=False) == 0
#check_intrinsics.main()
print('llvm.__version__: %s' % llvm.__version__)
#assert llvm.__version__ == '0.12.0'

View file

@ -1,6 +0,0 @@
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

@ -1,13 +0,0 @@
#!/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

@ -1,28 +0,0 @@
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

@ -1,19 +0,0 @@
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
contain the root `toctree` directive.
Documentation for llvmpy
========================
llvmpy
======
Contents:
@ -22,7 +22,7 @@ Contents:
Indices and tables
==================
------------------
* :ref:`genindex`
* :ref:`modindex`

152
example/vector_instr.py Normal file
View file

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

View file

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

25
llvm/deprecated.py Normal file
View file

@ -0,0 +1,25 @@
"""
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,3 +238,27 @@ 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)

View file

@ -80,6 +80,15 @@ 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):
@ -311,13 +320,15 @@ class TargetTransformInfo(Pass):
# Helpers
#===----------------------------------------------------------------------===
def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False,
inline_threshold=2000, pm=True, fpm=True, mod=None):
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):
'''
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.
@ -326,6 +337,18 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, 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:
@ -338,22 +361,27 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, 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)

View file

@ -191,6 +191,10 @@ 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):

View file

@ -12,7 +12,7 @@ tests = [] # stores unittest.TestCase objects
isolated_tests = [] # stores modue name
def run(verbosity=1):
def run(verbosity=1, run_isolated=True):
print('llvmpy is installed in: ' + os.path.dirname(__file__))
print('llvmpy version: ' + llvm.__version__)
print(sys.version)
@ -37,23 +37,32 @@ def run(verbosity=1):
if sys.version_info[:2] > (2, 6):
kwargs['buffer'] = True
runner = unittest.TextTestRunner(**kwargs)
testresult = runner.run(suite)
if testresult:
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:
# 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, end='')
p.wait()
if p.returncode:
raise Exception("%s returned: %d" % p.returncode)
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))
return testresult

View file

@ -1,28 +0,0 @@
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()

24
llvm/tests/test_alloca.py Normal file
View file

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

View file

@ -1,5 +1,5 @@
import unittest
from llvm.core import Type
from llvm.core import Type, Module, Builder, Constant
from .support import TestCase, tests
class TestStruct(TestCase):
@ -8,6 +8,19 @@ 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__':

0
llvm/utils/__init__.py Normal file
View file

View file

@ -0,0 +1,181 @@
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,7 +12,11 @@ http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf
"""
import sys, os, subprocess
import sys
import os
import subprocess
import contextlib
def detect_avx_support(option='detect'):
'''Detect AVX support'''
@ -36,13 +40,25 @@ def detect_unix_like():
except IOError:
return False
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
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()
def detect_osx_like():
try:
@ -50,9 +66,11 @@ def detect_osx_like():
stdout=subprocess.PIPE)
except OSError:
return False
features = info.stdout.read().decode('UTF8')
features = features.split()
return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features
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
if __name__ == '__main__':

View file

@ -349,7 +349,7 @@ class CBuilder(object):
elif not isinstance(count, lc.Value):
count = self.constant(types.int, count).value
ptr = self.builder.alloca_array(ty, count, name=name)
ptr = self.builder.alloca(ty, size=count, name=name)
return CArray(self, ptr)
def ret(self, val=None):

View file

@ -1,55 +1,95 @@
#include <Python.h>
#include <structmember.h>
#include <python3adapt.h>
#include <capsulethunk.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
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);
PyObject* GetAPIModule(){
if (NULL == TheAPIModule)
TheAPIModule = PyImport_ImportModule("llvmpy._api");
return TheAPIModule;
}
static
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);
PyObject* GetCapsuleModule(){
if (NULL == TheCapsuleModule)
TheCapsuleModule = PyImport_ImportModule("llvmpy.capsule");
return TheCapsuleModule;
}
static
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;
}
PyObject* GetCapsuleClass() {
if (NULL == TheCapsuleClass)
TheCapsuleClass = PyObject_GetAttrString(GetCapsuleModule(),
"Capsule");
return TheCapsuleClass;
}
// ------------------
// PyCapsule Context
// ------------------
static
PyObject* GetWrapperClass() {
if (NULL == TheWrapperClass)
TheWrapperClass = PyObject_GetAttrString(GetCapsuleModule(),
"Wrapper");
return TheWrapperClass;
}
static
CapsuleContext* getContext(PyObject* self, PyObject* args) {
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
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) {
void* context = PyCapsule_GetContext(obj);
if (!context) {
PyErr_SetString(PyExc_TypeError, "PyCapsule has no context.");
@ -59,9 +99,8 @@ CapsuleContext* getContext(PyObject* self, PyObject* args) {
}
static
PyObject* getClassName(PyObject* self, PyObject* args) {
CapsuleContext* context = getContext(self, args);
//Assert(context->_magic == 0xdead);
PyObject* GetClassName(PyObject* obj) {
CapsuleContext* context = GetContext(obj);
if (!context) {
return NULL;
} else {
@ -69,6 +108,476 @@ PyObject* getClassName(PyObject* self, PyObject* args) {
}
}
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[] = {
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
@ -76,6 +585,10 @@ static PyMethodDef core_methods[] = {
declmethod(getPointer),
declmethod(check),
declmethod(getClassName),
declmethod(unwrap),
declmethod(wrap),
declmethod(has_ownership),
declmethod(downcast),
{ NULL },
#undef declmethod
};
@ -106,10 +619,21 @@ 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
}

View file

@ -1,19 +1,27 @@
from weakref import WeakKeyDictionary, WeakValueDictionary, ref
from weakref import WeakValueDictionary
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.
@ -28,79 +36,63 @@ 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."
#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)
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 = {}
@ -108,15 +100,16 @@ _pyclasses = {}
# NOTE: The same 'addr' may appear in multiple class bins.
_cache = defaultdict(WeakValueDictionary)
def release_ownership(old):
logger.debug('Release %s', old)
addr = Capsule.getPointer(old)
name = Capsule.getName(old)
addr = getPointer(old)
name = getName(old)
if _addr2dtor.get((name, addr)) is None:
clsname = Capsule.getClassName(old)
clsname = getClassName(old)
if not _pyclasses[clsname]._has_dtor():
return
# Guard duplicated release
# Guard duplicated release
raise Exception("Already released")
_addr2dtor[(name, addr)] = None
@ -126,61 +119,86 @@ def obtain_ownership(cap):
if cls._has_dtor():
addr = cap.pointer
name = cap.name
assert _addr2dtor[addr] is None
assert _addr2dtor[(name, 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 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
#def has_ownership(cap):
# addr = Capsule.getPointer(cap)
# name = Capsule.getName(cap)
# return _addr2dtor.get((name, addr)) is not None
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 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):
'''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
@ -193,10 +211,11 @@ class Wrapper(object):
return hash(self._capsule)
def __eq__(self, other):
return self._capsule == other._capsule
if isinstance(other, Wrapper):
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)
@ -205,24 +224,25 @@ 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

View file

@ -1,5 +1,4 @@
import inspect, textwrap
import functools
import codegen as cg
import os
@ -8,10 +7,12 @@ namespaces = {}
RESERVED = frozenset(['None'])
def makedir(directory):
if not os.path.exists(directory):
os.makedirs(directory)
class SubModule(object):
def __init__(self):
self.methods = []
@ -293,6 +294,10 @@ 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:
@ -399,6 +404,7 @@ class Enum(object):
writer.println(fmt % locals())
writer.println()
class Method(object):
_kind_ = 'meth'
@ -516,6 +522,7 @@ 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)
@ -594,6 +601,7 @@ class CustomFunction(Function):
def fullname(self):
return self.realname
class Destructor(Method):
_kind_ = 'dtor'
@ -625,6 +633,7 @@ class Constructor(StaticMethod):
ret = writer.declare(retty.fullname, stmt)
return ret
class ref(_Type):
def __init__(self, element):
assert isinstance(element, Class), type(element)
@ -686,13 +695,16 @@ 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'
@ -757,6 +769,7 @@ class CustomPythonMethod(object):
for line in self.sourcelines:
writer.println(line)
class CustomPythonStaticMethod(CustomPythonMethod):
def compile_py(self, writer):
writer.println('@staticmethod')
@ -845,6 +858,7 @@ 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)

View file

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

View file

@ -40,7 +40,7 @@
namespace extra{
using namespace llvm;
class raw_svector_ostream_helper: public raw_svector_ostream {
SmallVectorImpl<char> *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<llvm::Type*, 8> 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) {
PyObject* cap = pycapsule_new(&*begin, capsuleName, className);
PyList_Append(list, cap);
auto_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) {
PyObject* cap = pycapsule_new(*begin, capsuleName, className);
PyList_Append(list, cap);
auto_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<GenericValue*>(
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();
PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size());
auto_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,6 +861,27 @@ 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;
@ -870,7 +891,8 @@ public:
inline virtual void passEnumerate(const llvm::PassInfo * pass_info){
PyObject* passArg = PyString_FromString(pass_info->getPassArgument());
PyObject* passName = PyString_FromString(pass_info->getPassName());
PyList_Append(List, Py_BuildValue("(OO)", passArg, passName));
auto_pyobject pair = Py_BuildValue("(OO)", passArg, passName);
PyList_Append(List, *pair);
}
};
@ -988,7 +1010,7 @@ fail:
}
static
PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
llvm::MCInst &instr,
const llvm::MemoryObject &region,
uint64_t address
@ -998,7 +1020,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);
}
@ -1046,5 +1068,5 @@ PyObject* llvm_sys_isBigEndianHost()
else
Py_RETURN_FALSE;
}
#endif
#endif

View file

@ -1,12 +1,13 @@
from binding import *
from .namespace import llvm
from .Value import Function, BasicBlock
from .Value import Function, BasicBlock, Value
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),

View file

@ -346,6 +346,9 @@ 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

View file

@ -26,3 +26,10 @@ 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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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