Compare commits
153 commits
improvefun
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34900d2748 | ||
|
|
749b518b90 | ||
|
|
c07fce0477 | ||
|
|
7f8476dd33 | ||
|
|
57afefb069 | ||
|
|
0629ccb226 | ||
|
|
6e4620edc6 | ||
|
|
2410267c8e | ||
|
|
bc12aae8c1 | ||
|
|
6578412437 | ||
|
|
ce696c9b4e | ||
|
|
3befa1be59 | ||
|
|
a9174f09c5 | ||
|
|
b86cc097d9 | ||
|
|
0e9f434ad8 | ||
|
|
e868b825bb | ||
|
|
dd2a569d76 | ||
|
|
059192f1ae | ||
|
|
3db6d8352a | ||
|
|
00db78d89e | ||
|
|
d9eb3ec175 | ||
|
|
4ed8f80774 | ||
|
|
43095609c3 | ||
|
|
b9cccbf9ae | ||
|
|
8689d62f02 | ||
|
|
17d3cef4bd | ||
|
|
ecac668bef | ||
|
|
078f1fe5c1 | ||
|
|
b9752e1e98 | ||
|
|
f8c1c78df1 | ||
|
|
b8e0338da8 | ||
|
|
091a393d1d | ||
|
|
d7590fb029 | ||
|
|
c199881b67 | ||
|
|
fb3b6a3674 | ||
|
|
4e814b7d53 | ||
|
|
8a6dd7af7f | ||
|
|
d08095299e | ||
|
|
bf5859be7e | ||
|
|
18d3b4809f | ||
|
|
a82e876f93 | ||
|
|
1f7b9e3922 | ||
|
|
fac1bc782d | ||
|
|
ea452bd33c | ||
|
|
ddf2007553 | ||
|
|
e7a7896710 | ||
|
|
69a78d0a54 | ||
|
|
cc4e4631bd | ||
|
|
8034854ad4 | ||
|
|
733fd7d18e | ||
|
|
6e55bfc406 | ||
|
|
72192c7e6a | ||
|
|
b303fd532a | ||
|
|
aa264cee2d | ||
|
|
3743146121 | ||
|
|
8de5c3faff | ||
|
|
083586464b | ||
|
|
0f3d5a8127 | ||
|
|
3e77a55de3 | ||
|
|
65c4558cac | ||
|
|
43f7330fda | ||
|
|
1d735e49d2 | ||
|
|
fea82991c3 | ||
|
|
b3bf7f86cd | ||
|
|
3c06f0d590 | ||
|
|
cadc53f174 | ||
|
|
0ed471d336 | ||
|
|
7234b0d200 | ||
|
|
fa3aec8353 | ||
|
|
bd9d71c713 | ||
|
|
8dbfc377ad | ||
|
|
82d9c787f3 | ||
|
|
87d444c9e9 | ||
|
|
fa26aa1651 | ||
|
|
cbf4a61a17 | ||
|
|
0e265a2cc5 | ||
|
|
e65f6174a7 | ||
|
|
83299a20a6 | ||
|
|
97c0e15e72 | ||
|
|
4eab936224 | ||
|
|
78be6a7f5f | ||
|
|
bc02b3d90a | ||
|
|
aa0ee9b6a6 | ||
|
|
0610a27535 | ||
|
|
f4bbb18e47 | ||
|
|
25e6651055 | ||
|
|
38a00c6e55 | ||
|
|
818c9289fc | ||
|
|
ba03b226c8 | ||
|
|
8f2c27ba41 | ||
|
|
ef59848d18 | ||
|
|
4905743e0a | ||
|
|
09d9dbba1e | ||
|
|
aae25f5e55 | ||
|
|
af2c1d6d01 | ||
|
|
4e993570cd | ||
|
|
6bbf53241d | ||
|
|
0801df41dc | ||
|
|
24f1b33737 | ||
|
|
536bc37c94 | ||
|
|
351bd39814 | ||
|
|
33ca795e0c | ||
|
|
d57c4d88c6 | ||
|
|
328f88bbd5 | ||
|
|
ea5b430297 | ||
|
|
5f01343bba | ||
|
|
bf8693bb80 | ||
|
|
e69048ad3d | ||
|
|
8480d55faf | ||
|
|
7d1c4c18a0 | ||
|
|
07c64779d8 | ||
|
|
d10b182479 | ||
|
|
1be8b07ced | ||
|
|
3a289ccace | ||
|
|
bf0253c9f9 | ||
|
|
d060c10096 | ||
|
|
1ed3c77310 | ||
|
|
cfe5e9ea92 | ||
|
|
1e9d37a64e | ||
|
|
eb4fc653f2 | ||
|
|
b4d943a671 | ||
|
|
c20c4d776f | ||
|
|
84a95945ea | ||
|
|
0421ad8456 | ||
|
|
2a25b1c2b3 | ||
|
|
c4db61c7f5 | ||
|
|
c0e9dedc90 | ||
|
|
319984f0e0 | ||
|
|
56a511854a | ||
|
|
625858aa6f | ||
|
|
6d3253e4ea | ||
|
|
4c1b9016fb | ||
|
|
2338eae5f6 | ||
|
|
2415042a2a | ||
|
|
ad287faeb1 | ||
|
|
69c75355f4 | ||
|
|
84f1b433de | ||
|
|
2e8944916c | ||
|
|
17ec89e457 | ||
|
|
6b333e84aa | ||
|
|
009239713e | ||
|
|
1812cff2d0 | ||
|
|
a0eb03b239 | ||
|
|
5b2b878f24 | ||
|
|
edab81ed7e | ||
|
|
96dc907613 | ||
|
|
592f9c6988 | ||
|
|
331f71f26f | ||
|
|
db7323771f | ||
|
|
f4b320ff09 | ||
|
|
08bed7dd74 | ||
|
|
c118427118 | ||
|
|
3e0dc25070 |
144 changed files with 8730 additions and 2122 deletions
37
CHANGELOG
37
CHANGELOG
|
|
@ -1,3 +1,40 @@
|
||||||
|
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)
|
||||||
|
* various bug fixes
|
||||||
|
|
||||||
2013-03-05 0.11.1:
|
2013-03-05 0.11.1:
|
||||||
--------------------
|
--------------------
|
||||||
* fix test when cc is not available
|
* fix test when cc is not available
|
||||||
|
|
|
||||||
|
|
@ -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 llvm *
|
||||||
|
recursive-include llvmpy *
|
||||||
recursive-include www *
|
recursive-include www *
|
||||||
recursive-include test *
|
recursive-include test *
|
||||||
recursive-include tools *
|
recursive-include tools *
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,14 @@ 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`` 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
|
**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::
|
||||||
|
|
||||||
$ git clone git@github.com:llvmpy/llvmpy.git
|
$ git clone git@github.com:llvmpy/llvmpy.git
|
||||||
|
|
|
||||||
6
buildscripts/condarecipe/bld.bat
Normal file
6
buildscripts/condarecipe/bld.bat
Normal 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
|
||||||
13
buildscripts/condarecipe/build.sh
Normal file
13
buildscripts/condarecipe/build.sh
Normal 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
|
||||||
28
buildscripts/condarecipe/meta.yaml
Normal file
28
buildscripts/condarecipe/meta.yaml
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package:
|
||||||
|
name: llvmpy
|
||||||
|
version: 99.9.9
|
||||||
|
|
||||||
|
source:
|
||||||
|
git_url: git@github.com:llvmpy/llvmpy.git
|
||||||
|
# git_tag: 0.12.0
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
build:
|
||||||
|
- llvm
|
||||||
|
- python
|
||||||
|
#- chrpath [linux]
|
||||||
|
run:
|
||||||
|
- llvm [unix]
|
||||||
|
- python
|
||||||
|
|
||||||
|
test:
|
||||||
|
imports:
|
||||||
|
- llvm
|
||||||
|
- llvmpy
|
||||||
|
- llvmpy._api
|
||||||
|
- llvmpy._capsule
|
||||||
|
- llpython
|
||||||
|
- llvm_array
|
||||||
|
- llvm_cbuilder
|
||||||
|
|
||||||
|
|
||||||
22
buildscripts/condarecipe/run_test.py
Normal file
22
buildscripts/condarecipe/run_test.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
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()
|
||||||
|
|
||||||
|
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, run_isolated=False) == 0
|
||||||
|
#check_intrinsics.main()
|
||||||
|
|
||||||
|
print('llvm.__version__: %s' % llvm.__version__)
|
||||||
|
#assert llvm.__version__ == '0.12.0'
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
Documentation for llvmpy
|
llvmpy
|
||||||
========================
|
======
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@ Contents:
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
------------------
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
|
|
|
||||||
152
example/vector_instr.py
Normal file
152
example/vector_instr.py
Normal 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()
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import opcode
|
import opcode
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import dis
|
import dis
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
'''Defines a bytecode based LLVM translator for llpython code.
|
'''Defines a bytecode based LLVM translator for llpython code.
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import itertools
|
import itertools
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from . import opcode_util
|
from . import opcode_util
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import sys
|
import sys
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import dis
|
import dis
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin
|
from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
def doslice (in_string, lower, upper):
|
def doslice (in_string, lower, upper):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# ______________________________________________________________________
|
# ______________________________________________________________________
|
||||||
|
|
||||||
import llvm.core as lc
|
import llvm.core as lc
|
||||||
|
|
|
||||||
22
llrtc/Makefile
Normal file
22
llrtc/Makefile
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
all:
|
||||||
|
make -C lib
|
||||||
|
|
||||||
|
ir:
|
||||||
|
make -C lib ir
|
||||||
|
|
||||||
|
test:
|
||||||
|
make -C lib test
|
||||||
|
|
||||||
|
clean-test:
|
||||||
|
make -C lib clean-test
|
||||||
|
|
||||||
|
clean-temp:
|
||||||
|
make -C lib clean-temp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C lib clean
|
||||||
|
|
||||||
|
install: ir
|
||||||
|
cp llrt_*.ll ../llvm/llrt
|
||||||
|
make -C lib clean-temp
|
||||||
|
|
||||||
25
llrtc/README.md
Normal file
25
llrtc/README.md
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# LLRT: Low Level Runtime
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
The same reason for LLVM compiler-rt. LLVM generates libgcc symbols, such as
|
||||||
|
__divdi3 for 64-bit division on 32-bit platform. They are not also available.
|
||||||
|
We need to ship compiler-rt but it is not Windows ready.
|
||||||
|
This subproject aims to provide a small portable subset of compiler-rt.
|
||||||
|
Start small and add only the things we really needed.
|
||||||
|
Performance is not crucial but should not be terrible.
|
||||||
|
Functionality and usefullness should be more important than performance.
|
||||||
|
|
||||||
|
## Developer Instructions
|
||||||
|
|
||||||
|
LLRT implements some functionalities in compiler-rt in ANSI C.
|
||||||
|
The C files are compiled using clang to produce LLVM IR which are shipped.
|
||||||
|
The IR files are committed in the repository.
|
||||||
|
So, remember to build the IR files commit them after modifying the C files.
|
||||||
|
|
||||||
|
## Build Requirement
|
||||||
|
|
||||||
|
- Make
|
||||||
|
- Clang
|
||||||
|
- Python
|
||||||
|
|
||||||
4
llrtc/lib/.gitignore
vendored
Normal file
4
llrtc/lib/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.o
|
||||||
|
*.run
|
||||||
|
*.out
|
||||||
|
*.ll
|
||||||
66
llrtc/lib/Makefile
Normal file
66
llrtc/lib/Makefile
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
OUTPUT = llrt
|
||||||
|
SOURCES = udivmod64.c sdivmod64.c div64.c mod64.c
|
||||||
|
TESTS = test_udivmod64.c test_sdivmod64.c
|
||||||
|
|
||||||
|
CLANG = clang
|
||||||
|
LLVM_LINK = llvm-link
|
||||||
|
CF = -Wall -ansi
|
||||||
|
CF_TEST = $(CF) -ftrapv
|
||||||
|
CF_BUILD = $(CF) -O0 -emit-llvm
|
||||||
|
OUTDIR = ..
|
||||||
|
STRIPPER = ../tools/striptriple.py
|
||||||
|
|
||||||
|
all: ir
|
||||||
|
|
||||||
|
ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll
|
||||||
|
|
||||||
|
$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc)
|
||||||
|
$(LLVM_LINK) -S $+ -o $@
|
||||||
|
python $(STRIPPER) $@
|
||||||
|
|
||||||
|
$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc)
|
||||||
|
$(LLVM_LINK) -S $+ -o $@
|
||||||
|
python $(STRIPPER) $@
|
||||||
|
|
||||||
|
build-test: $(SOURCES:.c=.o) $(TESTS:.c=.run)
|
||||||
|
|
||||||
|
lib$(OUTPUT).a: $(SOURCES:.c=.o)
|
||||||
|
$(CLANG) -static $+ -o $@
|
||||||
|
|
||||||
|
test: $(TESTS:.c=.run)
|
||||||
|
for src in $+; do \
|
||||||
|
echo "testing $${src}"; \
|
||||||
|
python $${src%.*}.py > $${src%.*}.out; \
|
||||||
|
done;
|
||||||
|
|
||||||
|
clean-test:
|
||||||
|
rm -f *.out
|
||||||
|
rm -f *.o
|
||||||
|
rm -f *.run
|
||||||
|
|
||||||
|
clean-dist: clean-temp
|
||||||
|
rm -f *.ll
|
||||||
|
|
||||||
|
clean-temp:
|
||||||
|
rm -f *.bc
|
||||||
|
rm -f *.o
|
||||||
|
rm -f *.out
|
||||||
|
|
||||||
|
clean: clean-test clean-dist
|
||||||
|
|
||||||
|
%.c: llrt.h
|
||||||
|
|
||||||
|
%_x86.bc: %.c
|
||||||
|
$(CLANG) -m32 $(CF_BUILD) -c $< -o $@
|
||||||
|
|
||||||
|
%_x86_64.bc: %.c
|
||||||
|
$(CLANG) -m64 $(CF_BUILD) -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CLANG) $(CF_TEST) -c $<
|
||||||
|
|
||||||
|
%.run: %.c
|
||||||
|
$(CLANG) $(CF_TEST) -o $@ $+
|
||||||
|
|
||||||
|
test_udivmod64.run: udivmod64.o
|
||||||
|
test_sdivmod64.run: udivmod64.o sdivmod64.o
|
||||||
11
llrtc/lib/div64.c
Normal file
11
llrtc/lib/div64.c
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "llrt.h"
|
||||||
|
|
||||||
|
uint64_t udiv64(uint64_t dividend, uint64_t divisor)
|
||||||
|
{
|
||||||
|
return udivmod64(dividend, divisor, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t sdiv64(int64_t dividend, int64_t divisor)
|
||||||
|
{
|
||||||
|
return sdivmod64(dividend, divisor, NULL);
|
||||||
|
}
|
||||||
19
llrtc/lib/llrt.h
Normal file
19
llrtc/lib/llrt.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef LLRT_H_
|
||||||
|
#define LLRT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
#define BITS_PER_BYTE 8
|
||||||
|
|
||||||
|
uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder);
|
||||||
|
int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder);
|
||||||
|
|
||||||
|
uint64_t udiv64(uint64_t dividend, uint64_t divisor);
|
||||||
|
int64_t sdiv64(int64_t dividend, int64_t divisor);
|
||||||
|
|
||||||
|
uint64_t umod64(uint64_t dividend, uint64_t divisor);
|
||||||
|
int64_t smod64(int64_t dividend, int64_t divisor);
|
||||||
|
|
||||||
|
#endif /* LLRT_H_ */
|
||||||
|
|
||||||
15
llrtc/lib/mod64.c
Normal file
15
llrtc/lib/mod64.c
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "llrt.h"
|
||||||
|
|
||||||
|
uint64_t umod64(uint64_t dividend, uint64_t divisor)
|
||||||
|
{
|
||||||
|
uint64_t rem;
|
||||||
|
udivmod64(dividend, divisor, &rem);
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t smod64(int64_t dividend, int64_t divisor)
|
||||||
|
{
|
||||||
|
int64_t rem;
|
||||||
|
sdivmod64(dividend, divisor, &rem);
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
40
llrtc/lib/sdivmod64.c
Normal file
40
llrtc/lib/sdivmod64.c
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "llrt.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calls to udivmod64 internally.
|
||||||
|
Note: remainder uses sign of divisor.
|
||||||
|
*/
|
||||||
|
int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder)
|
||||||
|
{
|
||||||
|
int signbitidx = BITS_PER_BYTE * sizeof(dividend) - 1;
|
||||||
|
int signed_dividend = dividend < 0;
|
||||||
|
int signed_divisor = divisor < 0;
|
||||||
|
int signed_result = signed_divisor ^ signed_dividend;
|
||||||
|
|
||||||
|
int64_t quotient;
|
||||||
|
uint64_t udvd, udvr, uquotient, uremainder;
|
||||||
|
|
||||||
|
udvd = signed_dividend ? -dividend : dividend;
|
||||||
|
udvr = signed_divisor ? -divisor : divisor;
|
||||||
|
uquotient = udivmod64(udvd, udvr, &uremainder);
|
||||||
|
|
||||||
|
if (signed_result){
|
||||||
|
if (uremainder) {
|
||||||
|
quotient = -(int64_t)uquotient - 1;
|
||||||
|
} else {
|
||||||
|
quotient = -(int64_t)uquotient;
|
||||||
|
}
|
||||||
|
if (remainder) {
|
||||||
|
/* if signed, there could be unsigned overflow
|
||||||
|
causing undefined behavior */
|
||||||
|
*remainder = (uint64_t)dividend - (uint64_t)quotient * (uint64_t)divisor;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quotient = (int64_t)uquotient;
|
||||||
|
if (remainder) {
|
||||||
|
*remainder = signed_divisor ? -uremainder : uremainder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return quotient;
|
||||||
|
}
|
||||||
21
llrtc/lib/test_sdivmod64.c
Normal file
21
llrtc/lib/test_sdivmod64.c
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "llrt.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]){
|
||||||
|
int64_t n, d, q, r;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("invalid argument: %s dividend divisor", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sscanf(argv[1], "%lld", &n);
|
||||||
|
sscanf(argv[2], "%lld", &d);
|
||||||
|
|
||||||
|
q = sdivmod64(n, d, &r);
|
||||||
|
|
||||||
|
printf("%lld\n", q);
|
||||||
|
printf("%lld\n", r);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
56
llrtc/lib/test_sdivmod64.py
Normal file
56
llrtc/lib/test_sdivmod64.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
udt = os.path.join('.', 'test_sdivmod64.run')
|
||||||
|
|
||||||
|
def testcase(dividend, divisor):
|
||||||
|
print 'divmod64(%d, %d)' % (dividend, divisor)
|
||||||
|
|
||||||
|
procargs = ('%s %s %s' % (udt, dividend, divisor)).split()
|
||||||
|
result = subprocess.check_output(procargs)
|
||||||
|
gotQ, gotR = map(int, result.splitlines())
|
||||||
|
|
||||||
|
expectQ = dividend // divisor
|
||||||
|
expectR = dividend % divisor
|
||||||
|
|
||||||
|
print 'Q = %d, R = %d' % (gotQ, gotR)
|
||||||
|
|
||||||
|
if expectQ != gotQ:
|
||||||
|
raise ValueError("invalid quotient: got=%d but expect=%d" %
|
||||||
|
(gotQ, expectQ))
|
||||||
|
if expectR != gotR:
|
||||||
|
raise ValueError("invalid remainder: got=%d but expect=%d" %
|
||||||
|
(gotR, expectR))
|
||||||
|
print 'OK'
|
||||||
|
|
||||||
|
def testsequence():
|
||||||
|
subjects = [
|
||||||
|
(0, 1),
|
||||||
|
(0, 0xffffffff),
|
||||||
|
(1, 2),
|
||||||
|
(1, 983219),
|
||||||
|
(2, 2),
|
||||||
|
(3, 2),
|
||||||
|
(1024, 2),
|
||||||
|
(2048, 512),
|
||||||
|
(21321, 512),
|
||||||
|
(9329189, 1031),
|
||||||
|
(0xffffffff, 2),
|
||||||
|
(0xffffffff, 0xffff),
|
||||||
|
(0x1ffffffff, 2),
|
||||||
|
(0x1ffffffff, 0xffff),
|
||||||
|
(0xffff, 0xffffffff),
|
||||||
|
(0x0fffffffffffffff, 0xffff),
|
||||||
|
(0x7fffffffffffffff, 0x7fffffffffffffff),
|
||||||
|
(0x7fffffffffffffff, 0x7ffffffffffffff0),
|
||||||
|
(0x7fffffffffffffff, 87655678587161901),
|
||||||
|
]
|
||||||
|
|
||||||
|
for dvd, dvr in subjects:
|
||||||
|
testcase(dvd, dvr)
|
||||||
|
testcase(dvd, -dvr)
|
||||||
|
testcase(-dvd, dvr)
|
||||||
|
testcase(-dvd, -dvr)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
testsequence()
|
||||||
20
llrtc/lib/test_udivmod64.c
Normal file
20
llrtc/lib/test_udivmod64.c
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "llrt.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]){
|
||||||
|
uint64_t n, d, q, r;
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("invalid argument: %s dividend divisor", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sscanf(argv[1], "%llu", &n);
|
||||||
|
sscanf(argv[2], "%llu", &d);
|
||||||
|
|
||||||
|
q = udivmod64(n, d, &r);
|
||||||
|
|
||||||
|
printf("%llu\n", q);
|
||||||
|
printf("%llu\n", r);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
53
llrtc/lib/test_udivmod64.py
Normal file
53
llrtc/lib/test_udivmod64.py
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
udt = os.path.join('.', 'test_udivmod64.run')
|
||||||
|
|
||||||
|
def testcase(dividend, divisor):
|
||||||
|
print 'divmod64(%d, %d)' % (dividend, divisor)
|
||||||
|
|
||||||
|
procargs = ('%s %s %s' % (udt, dividend, divisor)).split()
|
||||||
|
result = subprocess.check_output(procargs)
|
||||||
|
gotQ, gotR = map(int, result.splitlines())
|
||||||
|
|
||||||
|
expectQ = dividend // divisor
|
||||||
|
expectR = dividend % divisor
|
||||||
|
|
||||||
|
print 'Q = %d, R = %d' % (gotQ, gotR)
|
||||||
|
|
||||||
|
if expectQ != gotQ:
|
||||||
|
raise ValueError("invalid quotient: got=%d but expect=%d" %
|
||||||
|
(gotQ, expectQ))
|
||||||
|
if expectR != gotR:
|
||||||
|
raise ValueError("invalid remainder: got=%d but expect=%d" %
|
||||||
|
(gotR, expectR))
|
||||||
|
print 'OK'
|
||||||
|
|
||||||
|
def testsequence():
|
||||||
|
subjects = [
|
||||||
|
(0, 1),
|
||||||
|
(0, 0xffffffffffffffff),
|
||||||
|
(1, 2),
|
||||||
|
(1, 983219),
|
||||||
|
(2, 2),
|
||||||
|
(3, 2),
|
||||||
|
(1024, 2),
|
||||||
|
(2048, 512),
|
||||||
|
(21321, 512),
|
||||||
|
(9329189, 1031),
|
||||||
|
(0xffffffff, 2),
|
||||||
|
(0xffffffff, 0xffff),
|
||||||
|
(0x1ffffffff, 2),
|
||||||
|
(0x1ffffffff, 0xffff),
|
||||||
|
(0xffff, 0xffffffff),
|
||||||
|
(0xffffffffffffffff, 0xffff),
|
||||||
|
(0xffffffffffffffff, 0x7fffffffffffffff),
|
||||||
|
(0xffffffffffffffff, 0xfffffffffffffff0),
|
||||||
|
(0xffffffffffffffff, 87655678587161901),
|
||||||
|
]
|
||||||
|
|
||||||
|
for dvd, dvr in subjects:
|
||||||
|
testcase(dvd, dvr)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
testsequence()
|
||||||
84
llrtc/lib/udivmod64.c
Normal file
84
llrtc/lib/udivmod64.c
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
Implements unsigned divmod using for platform missing 64-bit division and/or
|
||||||
|
modulo functions.
|
||||||
|
*/
|
||||||
|
#include "llrt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
count left zero for 64-bit words
|
||||||
|
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int clz64(uint64_t x)
|
||||||
|
{
|
||||||
|
const int total_bits = sizeof(x) * BITS_PER_BYTE;
|
||||||
|
int zc = 0;
|
||||||
|
|
||||||
|
while (zc < total_bits && ((x >> (total_bits - zc - 1)) & 1) == 0) {
|
||||||
|
++zc;
|
||||||
|
}
|
||||||
|
return zc;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct div_state_
|
||||||
|
{
|
||||||
|
uint64_t tmp, dvd;
|
||||||
|
} div_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Left shift div_state by 1 bit
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void div_state_lshift(div_state *state)
|
||||||
|
{
|
||||||
|
state->tmp = (state->tmp << 1) | (state->dvd >> 63);
|
||||||
|
state->dvd = state->dvd << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Division of unsigned 64-bit word using 64-bit addition and subtration following
|
||||||
|
the shift-restore division algorithm.
|
||||||
|
For those interested in 32-bit implementation,
|
||||||
|
mapping of 64-bit addition and subtraction to 32-bit should be trivial.
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
- IBM. The PowerPC Compiler Writer's Guide
|
||||||
|
- LLVM compiler-rt
|
||||||
|
|
||||||
|
Assumptions:
|
||||||
|
- all operands and results are positive
|
||||||
|
- unsigned wrapped around
|
||||||
|
*/
|
||||||
|
uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
|
||||||
|
{
|
||||||
|
div_state state = {0, dividend};
|
||||||
|
uint64_t quotient = 0;
|
||||||
|
int i;
|
||||||
|
int skipahead;
|
||||||
|
|
||||||
|
if (divisor == 0) {
|
||||||
|
return 1 / 0; /* intentionally div by zero */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
skipahead to reduce iteration
|
||||||
|
*/
|
||||||
|
skipahead = clz64(dividend);
|
||||||
|
|
||||||
|
for (i = 0; i < skipahead; ++i) {
|
||||||
|
div_state_lshift(&state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
division loop
|
||||||
|
*/
|
||||||
|
for (i = skipahead; i < 64; ++i) {
|
||||||
|
div_state_lshift(&state);
|
||||||
|
if (state.tmp >= divisor) {
|
||||||
|
state.tmp = state.tmp - divisor;
|
||||||
|
quotient |= 1ull << (63 - i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (remainder) *remainder = state.tmp;
|
||||||
|
return quotient;
|
||||||
|
}
|
||||||
15
llrtc/tools/striptriple.py
Normal file
15
llrtc/tools/striptriple.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
buf = []
|
||||||
|
with open(sys.argv[1], 'r') as fin:
|
||||||
|
tripleline = re.compile('^target\s+triple\s+=\s+')
|
||||||
|
for line in fin.readlines():
|
||||||
|
if not tripleline.match(line):
|
||||||
|
buf.append(line)
|
||||||
|
|
||||||
|
with open(sys.argv[1], 'w') as fout:
|
||||||
|
for line in buf:
|
||||||
|
fout.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,6 +2,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
from distutils.spawn import find_executable
|
from distutils.spawn import find_executable
|
||||||
from os.path import abspath, dirname, isfile, join
|
from os.path import abspath, dirname, isfile, join
|
||||||
|
from os import listdir
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -39,55 +40,17 @@ def libs_options():
|
||||||
# NOTE: instead of actually looking at the components requested,
|
# NOTE: instead of actually looking at the components requested,
|
||||||
# we just print out a bunch of libs
|
# we just print out a bunch of libs
|
||||||
for lib in """
|
for lib in """
|
||||||
LLVMAnalysis
|
|
||||||
LLVMAsmParser
|
|
||||||
LLVMAsmPrinter
|
|
||||||
LLVMBitReader
|
|
||||||
LLVMBitWriter
|
|
||||||
LLVMCodeGen
|
|
||||||
LLVMCore
|
|
||||||
LLVMExecutionEngine
|
|
||||||
LLVMInstCombine
|
|
||||||
LLVMInstrumentation
|
|
||||||
LLVMInterpreter
|
|
||||||
LLVMipa
|
|
||||||
LLVMipo
|
|
||||||
LLVMJIT
|
|
||||||
LLVMLinker
|
|
||||||
LLVMMC
|
|
||||||
LLVMMCParser
|
|
||||||
LLVMObject
|
|
||||||
LLVMRuntimeDyld
|
|
||||||
LLVMScalarOpts
|
|
||||||
LLVMSelectionDAG
|
|
||||||
LLVMSupport
|
|
||||||
LLVMTarget
|
|
||||||
LLVMTransformUtils
|
|
||||||
LLVMVectorize
|
|
||||||
LLVMX86AsmParser
|
|
||||||
LLVMX86AsmPrinter
|
|
||||||
LLVMX86CodeGen
|
|
||||||
LLVMX86Desc
|
|
||||||
LLVMX86Disassembler
|
|
||||||
LLVMX86Info
|
|
||||||
LLVMX86Utils
|
|
||||||
Advapi32
|
Advapi32
|
||||||
Shell32
|
Shell32
|
||||||
""".split():
|
""".split():
|
||||||
print('-l%s' % lib)
|
print('-l%s' % lib)
|
||||||
|
|
||||||
if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')):
|
bpath = join(find_llvm_prefix(), 'lib')
|
||||||
print('-lLLVMPTXAsmPrinter')
|
for filename in listdir(bpath):
|
||||||
print('-lLLVMPTXCodeGen')
|
filepath = join(bpath, filename)
|
||||||
print('-lLLVMPTXDesc')
|
if isfile(filepath) and filename.endswith('.lib') and filename.startswith('LLVM'):
|
||||||
print('-lLLVMPTXInfo')
|
name = filename.split('.', 1)[0]
|
||||||
|
print('-l%s' % name)
|
||||||
elif isfile(join(find_llvm_prefix(), 'lib', 'LLVMNVPTXCodeGen.lib')):
|
|
||||||
print('-lLLVMNVPTXAsmPrinter')
|
|
||||||
print('-lLLVMNVPTXCodeGen')
|
|
||||||
print('-lLLVMNVPTXDesc')
|
|
||||||
print('-lLLVMNVPTXInfo')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
|
|
@ -98,12 +61,15 @@ def main():
|
||||||
if option == '--version':
|
if option == '--version':
|
||||||
print(get_llvm_version())
|
print(get_llvm_version())
|
||||||
|
|
||||||
|
elif option == '--targets-built':
|
||||||
|
print('X86') # just do X86
|
||||||
|
|
||||||
elif option == '--libs':
|
elif option == '--libs':
|
||||||
libs_options()
|
libs_options()
|
||||||
|
|
||||||
elif option == '--includedir':
|
elif option == '--includedir':
|
||||||
incdir = join(find_llvm_prefix(), 'include')
|
incdir = join(find_llvm_prefix(), 'include')
|
||||||
ensure_file(join(incdir, 'llvm' , 'BasicBlock.h'))
|
ensure_file(join(incdir, 'llvm' , 'Linker.h'))
|
||||||
print(incdir)
|
print(incdir)
|
||||||
|
|
||||||
elif option == '--libdir':
|
elif option == '--libdir':
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ del get_versions
|
||||||
|
|
||||||
|
|
||||||
from llvmpy import extra
|
from llvmpy import extra
|
||||||
|
|
||||||
version = extra.get_llvm_version()
|
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
|
||||||
|
|
@ -31,14 +34,14 @@ def _extract_ptrs(objs):
|
||||||
class LLVMException(Exception):
|
class LLVMException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test(verbosity=1):
|
def test(verbosity=3, run_isolated=True):
|
||||||
"""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.test_llvmpy import run
|
from llvm.tests import run
|
||||||
|
|
||||||
result = run(verbosity=verbosity)
|
result = run(verbosity=verbosity, run_isolated=run_isolated)
|
||||||
|
errct = len(result.failures) + len(result.errors)
|
||||||
return len(result.failures) + len(result.errors)
|
|
||||||
|
|
||||||
|
return errct
|
||||||
|
|
|
||||||
777
llvm/core.py
777
llvm/core.py
File diff suppressed because it is too large
Load diff
25
llvm/deprecated.py
Normal file
25
llvm/deprecated.py
Normal 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
|
||||||
213
llvm/ee.py
213
llvm/ee.py
|
|
@ -30,33 +30,23 @@
|
||||||
|
|
||||||
"Execution Engine and related classes."
|
"Execution Engine and related classes."
|
||||||
|
|
||||||
from io import BytesIO
|
import sys
|
||||||
import contextlib
|
|
||||||
|
|
||||||
import llvm
|
import llvm
|
||||||
from llvm import core
|
from llvm import core
|
||||||
from llvm.passes import TargetData, TargetTransformInfo
|
from llvm.passes import TargetData, TargetTransformInfo
|
||||||
from llvmpy import api, extra
|
from llvmpy import api, extra
|
||||||
|
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
# Enumerations
|
# import items which were moved to target module
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
|
from llvm.target import (initialize_all, initialize_target,
|
||||||
|
print_registered_targets, get_host_cpu_name, get_default_triple,
|
||||||
|
TargetMachine,
|
||||||
|
BO_BIG_ENDIAN, BO_LITTLE_ENDIAN,
|
||||||
|
CM_DEFAULT, CM_JITDEFAULT, CM_SMALL, CM_KERNEL, CM_MEDIUM, CM_LARGE,
|
||||||
|
RELOC_DEFAULT, RELOC_STATIC, RELOC_PIC, RELOC_DYNAMIC_NO_PIC)
|
||||||
|
|
||||||
BO_BIG_ENDIAN = 0
|
|
||||||
BO_LITTLE_ENDIAN = 1
|
|
||||||
|
|
||||||
# CodeModel
|
|
||||||
CM_DEFAULT = api.llvm.CodeModel.Model.Default
|
|
||||||
CM_JITDEFAULT = api.llvm.CodeModel.Model.JITDefault
|
|
||||||
CM_SMALL = api.llvm.CodeModel.Model.Small
|
|
||||||
CM_KERNEL = api.llvm.CodeModel.Model.Kernel
|
|
||||||
CM_MEDIUM = api.llvm.CodeModel.Model.Medium
|
|
||||||
CM_LARGE = api.llvm.CodeModel.Model.Large
|
|
||||||
|
|
||||||
# Reloc
|
|
||||||
RELOC_DEFAULT = api.llvm.Reloc.Model.Default
|
|
||||||
RELOC_STATIC = api.llvm.Reloc.Model.Static
|
|
||||||
RELOC_PIC = api.llvm.Reloc.Model.PIC_
|
|
||||||
RELOC_DYNAMIC_NO_PIC = api.llvm.Reloc.Model.DynamicNoPIC
|
|
||||||
|
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
# Generic value
|
# Generic value
|
||||||
|
|
@ -150,9 +140,17 @@ class EngineBuilder(llvm.Wrapper):
|
||||||
'''
|
'''
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
engine = self._ptr.create(tm._ptr)
|
engine = self._ptr.create(tm._ptr)
|
||||||
|
elif (sys.platform.startswith('win32') and
|
||||||
|
getattr(self, '_use_mcjit', False)):
|
||||||
|
# force ELF generation on MCJIT on win32
|
||||||
|
triple = get_default_triple()
|
||||||
|
tm = TargetMachine.new('%s-elf' % triple)
|
||||||
|
engine = self._ptr.create(tm._ptr)
|
||||||
else:
|
else:
|
||||||
engine = self._ptr.create()
|
engine = self._ptr.create()
|
||||||
return ExecutionEngine(engine)
|
ee = ExecutionEngine(engine)
|
||||||
|
ee.finalize_object() # no effect for legacy JIT
|
||||||
|
return ee
|
||||||
|
|
||||||
def select_target(self, *args):
|
def select_target(self, *args):
|
||||||
'''get the corresponding target machine
|
'''get the corresponding target machine
|
||||||
|
|
@ -167,6 +165,12 @@ class EngineBuilder(llvm.Wrapper):
|
||||||
ptr = self._ptr.selectTarget()
|
ptr = self._ptr.selectTarget()
|
||||||
return TargetMachine(ptr)
|
return TargetMachine(ptr)
|
||||||
|
|
||||||
|
def mcjit(self, enable):
|
||||||
|
'''Enable/disable MCJIT
|
||||||
|
'''
|
||||||
|
self._ptr.setUseMCJIT(enable)
|
||||||
|
self._use_mcjit = True
|
||||||
|
return self
|
||||||
|
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
# Execution engine
|
# Execution engine
|
||||||
|
|
@ -188,6 +192,9 @@ class ExecutionEngine(llvm.Wrapper):
|
||||||
ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args)))
|
ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args)))
|
||||||
return GenericValue(ptr)
|
return GenericValue(ptr)
|
||||||
|
|
||||||
|
def get_pointer_to_named_function(self, name, abort=True):
|
||||||
|
return self._ptr.getPointerToNamedFunction(name, abort)
|
||||||
|
|
||||||
def get_pointer_to_function(self, fn):
|
def get_pointer_to_function(self, fn):
|
||||||
return self._ptr.getPointerToFunction(fn._ptr)
|
return self._ptr.getPointerToFunction(fn._ptr)
|
||||||
|
|
||||||
|
|
@ -213,151 +220,45 @@ class ExecutionEngine(llvm.Wrapper):
|
||||||
def remove_module(self, module):
|
def remove_module(self, module):
|
||||||
return self._ptr.removeModule(module._ptr)
|
return self._ptr.removeModule(module._ptr)
|
||||||
|
|
||||||
|
def finalize_object(self):
|
||||||
|
return self._ptr.finalizeObject()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_data(self):
|
def target_data(self):
|
||||||
ptr = self._ptr.getDataLayout()
|
ptr = self._ptr.getDataLayout()
|
||||||
return TargetData(ptr)
|
return TargetData(ptr)
|
||||||
|
|
||||||
|
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
# Target machine
|
# Dynamic Library
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
|
|
||||||
def initialize_target(target, noraise=False):
|
def dylib_add_symbol(name, ptr):
|
||||||
"""Initialize target by name.
|
api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr)
|
||||||
It is safe to initialize the same target multiple times.
|
|
||||||
|
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
|
||||||
"""
|
"""
|
||||||
prefix = 'LLVMInitialize'
|
return DynamicLibrary(filename)
|
||||||
postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter']
|
|
||||||
try:
|
|
||||||
for postfix in postfixes:
|
|
||||||
getattr(api, '%s%s%s' % (prefix, target, postfix))()
|
|
||||||
except AttributeError:
|
|
||||||
if noraise:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def print_registered_targets():
|
class DynamicLibrary(object):
|
||||||
'''
|
def __init__(self, filename):
|
||||||
Note: print directly to stdout
|
"""
|
||||||
'''
|
Raises RuntimeError
|
||||||
api.llvm.TargetRegistry.printRegisteredTargetsForVersion()
|
"""
|
||||||
|
self._ptr = api.llvm.sys.DynamicLibrary.getPermanentLibrary(
|
||||||
def get_host_cpu_name():
|
filename)
|
||||||
'''return the string name of the host CPU
|
|
||||||
'''
|
|
||||||
return api.llvm.sys.getHostCPUName()
|
|
||||||
|
|
||||||
def get_default_triple():
|
|
||||||
'''return the target triple of the host in str-rep
|
|
||||||
'''
|
|
||||||
return api.llvm.sys.getDefaultTargetTriple()
|
|
||||||
|
|
||||||
|
|
||||||
class TargetMachine(llvm.Wrapper):
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT,
|
|
||||||
reloc=RELOC_DEFAULT):
|
|
||||||
if not triple:
|
|
||||||
triple = get_default_triple()
|
|
||||||
if not cpu:
|
|
||||||
cpu = get_host_cpu_name()
|
|
||||||
with contextlib.closing(BytesIO()) as error:
|
|
||||||
target = api.llvm.TargetRegistry.lookupTarget(triple, error)
|
|
||||||
if not target:
|
|
||||||
raise llvm.LLVMException(error)
|
|
||||||
if not target.hasTargetMachine():
|
|
||||||
raise llvm.LLVMException(target, "No target machine.")
|
|
||||||
target_options = api.llvm.TargetOptions.new()
|
|
||||||
tm = target.createTargetMachine(triple, cpu, features,
|
|
||||||
target_options,
|
|
||||||
reloc, cm, opt)
|
|
||||||
if not tm:
|
|
||||||
raise llvm.LLVMException("Cannot create target machine")
|
|
||||||
return TargetMachine(tm)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT,
|
|
||||||
reloc=RELOC_DEFAULT):
|
|
||||||
'''create a targetmachine given an architecture name
|
|
||||||
|
|
||||||
For a list of architectures,
|
|
||||||
use: `llc -help`
|
|
||||||
|
|
||||||
For a list of available CPUs,
|
|
||||||
use: `llvm-as < /dev/null | llc -march=xyz -mcpu=help`
|
|
||||||
|
|
||||||
For a list of available attributes (features),
|
|
||||||
use: `llvm-as < /dev/null | llc -march=xyz -mattr=help`
|
|
||||||
'''
|
|
||||||
triple = api.llvm.Triple.new()
|
|
||||||
with contextlib.closing(BytesIO()) as error:
|
|
||||||
target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error)
|
|
||||||
if not target:
|
|
||||||
raise llvm.LLVMException(error.getvalue())
|
|
||||||
if not target.hasTargetMachine():
|
|
||||||
raise llvm.LLVMException(target, "No target machine.")
|
|
||||||
target_options = api.llvm.TargetOptions.new()
|
|
||||||
tm = target.createTargetMachine(str(triple), cpu, features,
|
|
||||||
target_options,
|
|
||||||
reloc, cm, opt)
|
|
||||||
if not tm:
|
|
||||||
raise llvm.LLVMException("Cannot create target machine")
|
|
||||||
return TargetMachine(tm)
|
|
||||||
|
|
||||||
def _emit_file(self, module, cgft):
|
|
||||||
pm = api.llvm.PassManager.new()
|
|
||||||
os = extra.make_raw_ostream_for_printing()
|
|
||||||
pm.add(api.llvm.DataLayout.new(str(self.target_data)))
|
|
||||||
failed = self._ptr.addPassesToEmitFile(pm, os, cgft)
|
|
||||||
pm.run(module)
|
|
||||||
|
|
||||||
|
|
||||||
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
|
||||||
if cgft == CGFT.CGFT_ObjectFile:
|
|
||||||
return os.bytes()
|
|
||||||
else:
|
|
||||||
return os.str()
|
|
||||||
|
|
||||||
def emit_assembly(self, module):
|
|
||||||
'''returns byte string of the module as assembly code of the target machine
|
|
||||||
'''
|
|
||||||
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
|
||||||
return self._emit_file(module._ptr, CGFT.CGFT_AssemblyFile)
|
|
||||||
|
|
||||||
def emit_object(self, module):
|
|
||||||
'''returns byte string of the module as native code of the target machine
|
|
||||||
'''
|
|
||||||
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
|
||||||
return self._emit_file(module._ptr, CGFT.CGFT_ObjectFile)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def target_data(self):
|
|
||||||
'''get target data of this machine
|
|
||||||
'''
|
|
||||||
return TargetData(self._ptr.getDataLayout())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def target_name(self):
|
|
||||||
return self._ptr.getTarget().getName()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def target_short_description(self):
|
|
||||||
return self._ptr.getTarget().getShortDescription()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def triple(self):
|
|
||||||
return self._ptr.getTargetTriple()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cpu(self):
|
|
||||||
return self._ptr.getTargetCPU()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def feature_string(self):
|
|
||||||
return self._ptr.getTargetFeatureString()
|
|
||||||
|
|
||||||
|
def get_address_of_symbol(self, symbol):
|
||||||
|
"""
|
||||||
|
Get the address of `symbol` (str) as integer
|
||||||
|
"""
|
||||||
|
return self._ptr.getAddressOfSymbol(symbol)
|
||||||
|
|
|
||||||
79
llvm/llrt.py
Normal file
79
llvm/llrt.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import os
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.passes as lp
|
||||||
|
import llvm.ee as le
|
||||||
|
|
||||||
|
def replace_divmod64(lfunc):
|
||||||
|
'''Replaces all 64-bit integer division (sdiv, udiv) and modulo (srem, urem)
|
||||||
|
'''
|
||||||
|
int64 = lc.Type.int(64)
|
||||||
|
int64ptr = lc.Type.pointer(lc.Type.int(64))
|
||||||
|
|
||||||
|
functy = lc.Type.function(int64, [int64, int64])
|
||||||
|
udiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_udiv64')
|
||||||
|
sdiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_sdiv64')
|
||||||
|
umod64 = lfunc.module.get_or_insert_function(functy, '__llrt_umod64')
|
||||||
|
smod64 = lfunc.module.get_or_insert_function(functy, '__llrt_smod64')
|
||||||
|
|
||||||
|
builder = lc.Builder.new(lfunc.entry_basic_block)
|
||||||
|
for bb in lfunc.basic_blocks:
|
||||||
|
for inst in bb.instructions:
|
||||||
|
if inst.opcode_name == 'sdiv' and inst.type == int64:
|
||||||
|
_replace_with(builder, inst, sdiv64)
|
||||||
|
elif inst.opcode_name == 'udiv' and inst.type == int64:
|
||||||
|
_replace_with(builder, inst, udiv64)
|
||||||
|
elif inst.opcode_name == 'srem' and inst.type == int64:
|
||||||
|
_replace_with(builder, inst, smod64)
|
||||||
|
elif inst.opcode_name == 'urem' and inst.type == int64:
|
||||||
|
_replace_with(builder, inst, umod64)
|
||||||
|
|
||||||
|
def _replace_with(builder, inst, func):
|
||||||
|
'''Replace instruction with a call to the function with the same operands
|
||||||
|
as arguments.
|
||||||
|
'''
|
||||||
|
builder.position_before(inst)
|
||||||
|
replacement = builder.call(func, inst.operands)
|
||||||
|
inst.replace_all_uses_with(replacement._ptr)
|
||||||
|
inst.erase_from_parent()
|
||||||
|
|
||||||
|
def load(arch):
|
||||||
|
'''Load the LLRT module corresponding to the given architecture
|
||||||
|
Creates a new module and optimizes it using the information from
|
||||||
|
the host machine.
|
||||||
|
'''
|
||||||
|
if arch != 'x86_64':
|
||||||
|
arch = 'x86'
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'llrt', 'llrt_%s.ll' % arch)
|
||||||
|
with open(path) as fin:
|
||||||
|
lib = lc.Module.from_assembly(fin)
|
||||||
|
|
||||||
|
# run passes to optimize
|
||||||
|
tm = le.TargetMachine.new()
|
||||||
|
pms = lp.build_pass_managers(tm, opt=3, fpm=False)
|
||||||
|
pms.pm.run(lib)
|
||||||
|
return lib
|
||||||
|
|
||||||
|
class LLRT(object):
|
||||||
|
def __init__(self):
|
||||||
|
arch = le.get_default_triple().split('-', 1)[0]
|
||||||
|
self.module = load(arch)
|
||||||
|
self.engine = le.EngineBuilder.new(self.module).opt(3).create()
|
||||||
|
self.installed_symbols = set()
|
||||||
|
|
||||||
|
def install_symbols(self):
|
||||||
|
'''Bind all the external symbols to the global symbol map.
|
||||||
|
Any future reference to these symbols will be automatically resolved
|
||||||
|
by LLVM.
|
||||||
|
'''
|
||||||
|
for lfunc in self.module.functions:
|
||||||
|
if lfunc.linkage == lc.LINKAGE_EXTERNAL:
|
||||||
|
mangled = '__llrt_' + lfunc.name
|
||||||
|
self.installed_symbols.add(mangled)
|
||||||
|
ptr = self.engine.get_pointer_to_function(lfunc)
|
||||||
|
le.dylib_add_symbol(mangled, ptr)
|
||||||
|
|
||||||
|
def uninstall_symbols(self):
|
||||||
|
for sym in self.installed_symbols:
|
||||||
|
le.dylib_add_symbol(sym, 0)
|
||||||
|
|
||||||
|
|
||||||
371
llvm/llrt/llrt_x86.ll
Normal file
371
llvm/llrt/llrt_x86.ll
Normal file
|
|
@ -0,0 +1,371 @@
|
||||||
|
; ModuleID = 'udivmod64_x86.bc'
|
||||||
|
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128"
|
||||||
|
|
||||||
|
%struct.div_state_ = type { i64, i64 }
|
||||||
|
|
||||||
|
define i64 @udivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 4
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%3 = alloca i64, align 8
|
||||||
|
%4 = alloca i64*, align 4
|
||||||
|
%state = alloca %struct.div_state_, align 4
|
||||||
|
%quotient = alloca i64, align 8
|
||||||
|
%i = alloca i32, align 4
|
||||||
|
%skipahead = alloca i32, align 4
|
||||||
|
store i64 %dividend, i64* %2, align 8
|
||||||
|
store i64 %divisor, i64* %3, align 8
|
||||||
|
store i64* %remainder, i64** %4, align 4
|
||||||
|
%5 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
store i64 0, i64* %5, align 4
|
||||||
|
%6 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 1
|
||||||
|
%7 = load i64* %2, align 8
|
||||||
|
store i64 %7, i64* %6, align 4
|
||||||
|
store i64 0, i64* %quotient, align 8
|
||||||
|
%8 = load i64* %3, align 8
|
||||||
|
%9 = icmp eq i64 %8, 0
|
||||||
|
br i1 %9, label %10, label %11
|
||||||
|
|
||||||
|
; <label>:10 ; preds = %0
|
||||||
|
store i64 0, i64* %1
|
||||||
|
br label %57
|
||||||
|
|
||||||
|
; <label>:11 ; preds = %0
|
||||||
|
%12 = load i64* %2, align 8
|
||||||
|
%13 = call i32 @clz64(i64 %12)
|
||||||
|
store i32 %13, i32* %skipahead, align 4
|
||||||
|
store i32 0, i32* %i, align 4
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:14 ; preds = %19, %11
|
||||||
|
%15 = load i32* %i, align 4
|
||||||
|
%16 = load i32* %skipahead, align 4
|
||||||
|
%17 = icmp slt i32 %15, %16
|
||||||
|
br i1 %17, label %18, label %22
|
||||||
|
|
||||||
|
; <label>:18 ; preds = %14
|
||||||
|
call void @div_state_lshift(%struct.div_state_* %state)
|
||||||
|
br label %19
|
||||||
|
|
||||||
|
; <label>:19 ; preds = %18
|
||||||
|
%20 = load i32* %i, align 4
|
||||||
|
%21 = add nsw i32 %20, 1
|
||||||
|
store i32 %21, i32* %i, align 4
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:22 ; preds = %14
|
||||||
|
%23 = load i32* %skipahead, align 4
|
||||||
|
store i32 %23, i32* %i, align 4
|
||||||
|
br label %24
|
||||||
|
|
||||||
|
; <label>:24 ; preds = %45, %22
|
||||||
|
%25 = load i32* %i, align 4
|
||||||
|
%26 = icmp slt i32 %25, 64
|
||||||
|
br i1 %26, label %27, label %48
|
||||||
|
|
||||||
|
; <label>:27 ; preds = %24
|
||||||
|
call void @div_state_lshift(%struct.div_state_* %state)
|
||||||
|
%28 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%29 = load i64* %28, align 4
|
||||||
|
%30 = load i64* %3, align 8
|
||||||
|
%31 = icmp uge i64 %29, %30
|
||||||
|
br i1 %31, label %32, label %44
|
||||||
|
|
||||||
|
; <label>:32 ; preds = %27
|
||||||
|
%33 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%34 = load i64* %33, align 4
|
||||||
|
%35 = load i64* %3, align 8
|
||||||
|
%36 = sub i64 %34, %35
|
||||||
|
%37 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
store i64 %36, i64* %37, align 4
|
||||||
|
%38 = load i32* %i, align 4
|
||||||
|
%39 = sub nsw i32 63, %38
|
||||||
|
%40 = zext i32 %39 to i64
|
||||||
|
%41 = shl i64 1, %40
|
||||||
|
%42 = load i64* %quotient, align 8
|
||||||
|
%43 = or i64 %42, %41
|
||||||
|
store i64 %43, i64* %quotient, align 8
|
||||||
|
br label %44
|
||||||
|
|
||||||
|
; <label>:44 ; preds = %32, %27
|
||||||
|
br label %45
|
||||||
|
|
||||||
|
; <label>:45 ; preds = %44
|
||||||
|
%46 = load i32* %i, align 4
|
||||||
|
%47 = add nsw i32 %46, 1
|
||||||
|
store i32 %47, i32* %i, align 4
|
||||||
|
br label %24
|
||||||
|
|
||||||
|
; <label>:48 ; preds = %24
|
||||||
|
%49 = load i64** %4, align 4
|
||||||
|
%50 = icmp ne i64* %49, null
|
||||||
|
br i1 %50, label %51, label %55
|
||||||
|
|
||||||
|
; <label>:51 ; preds = %48
|
||||||
|
%52 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%53 = load i64* %52, align 4
|
||||||
|
%54 = load i64** %4, align 4
|
||||||
|
store i64 %53, i64* %54, align 4
|
||||||
|
br label %55
|
||||||
|
|
||||||
|
; <label>:55 ; preds = %51, %48
|
||||||
|
%56 = load i64* %quotient, align 8
|
||||||
|
store i64 %56, i64* %1
|
||||||
|
br label %57
|
||||||
|
|
||||||
|
; <label>:57 ; preds = %55, %10
|
||||||
|
%58 = load i64* %1
|
||||||
|
ret i64 %58
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal i32 @clz64(i64 %x) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%total_bits = alloca i32, align 4
|
||||||
|
%zc = alloca i32, align 4
|
||||||
|
store i64 %x, i64* %1, align 8
|
||||||
|
store i32 64, i32* %total_bits, align 4
|
||||||
|
store i32 0, i32* %zc, align 4
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:2 ; preds = %16, %0
|
||||||
|
%3 = load i32* %zc, align 4
|
||||||
|
%4 = icmp slt i32 %3, 64
|
||||||
|
br i1 %4, label %5, label %14
|
||||||
|
|
||||||
|
; <label>:5 ; preds = %2
|
||||||
|
%6 = load i64* %1, align 8
|
||||||
|
%7 = load i32* %zc, align 4
|
||||||
|
%8 = sub nsw i32 64, %7
|
||||||
|
%9 = sub nsw i32 %8, 1
|
||||||
|
%10 = zext i32 %9 to i64
|
||||||
|
%11 = lshr i64 %6, %10
|
||||||
|
%12 = and i64 %11, 1
|
||||||
|
%13 = icmp eq i64 %12, 0
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:14 ; preds = %5, %2
|
||||||
|
%15 = phi i1 [ false, %2 ], [ %13, %5 ]
|
||||||
|
br i1 %15, label %16, label %19
|
||||||
|
|
||||||
|
; <label>:16 ; preds = %14
|
||||||
|
%17 = load i32* %zc, align 4
|
||||||
|
%18 = add nsw i32 %17, 1
|
||||||
|
store i32 %18, i32* %zc, align 4
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:19 ; preds = %14
|
||||||
|
%20 = load i32* %zc, align 4
|
||||||
|
ret i32 %20
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @div_state_lshift(%struct.div_state_* %state) nounwind ssp {
|
||||||
|
%1 = alloca %struct.div_state_*, align 4
|
||||||
|
store %struct.div_state_* %state, %struct.div_state_** %1, align 4
|
||||||
|
%2 = load %struct.div_state_** %1, align 4
|
||||||
|
%3 = getelementptr inbounds %struct.div_state_* %2, i32 0, i32 0
|
||||||
|
%4 = load i64* %3, align 4
|
||||||
|
%5 = shl i64 %4, 1
|
||||||
|
%6 = load %struct.div_state_** %1, align 4
|
||||||
|
%7 = getelementptr inbounds %struct.div_state_* %6, i32 0, i32 1
|
||||||
|
%8 = load i64* %7, align 4
|
||||||
|
%9 = lshr i64 %8, 63
|
||||||
|
%10 = or i64 %5, %9
|
||||||
|
%11 = load %struct.div_state_** %1, align 4
|
||||||
|
%12 = getelementptr inbounds %struct.div_state_* %11, i32 0, i32 0
|
||||||
|
store i64 %10, i64* %12, align 4
|
||||||
|
%13 = load %struct.div_state_** %1, align 4
|
||||||
|
%14 = getelementptr inbounds %struct.div_state_* %13, i32 0, i32 1
|
||||||
|
%15 = load i64* %14, align 4
|
||||||
|
%16 = shl i64 %15, 1
|
||||||
|
%17 = load %struct.div_state_** %1, align 4
|
||||||
|
%18 = getelementptr inbounds %struct.div_state_* %17, i32 0, i32 1
|
||||||
|
store i64 %16, i64* %18, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @sdivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%3 = alloca i64*, align 4
|
||||||
|
%signbitidx = alloca i32, align 4
|
||||||
|
%signed_dividend = alloca i32, align 4
|
||||||
|
%signed_divisor = alloca i32, align 4
|
||||||
|
%signed_result = alloca i32, align 4
|
||||||
|
%quotient = alloca i64, align 8
|
||||||
|
%udvd = alloca i64, align 8
|
||||||
|
%udvr = alloca i64, align 8
|
||||||
|
%uquotient = alloca i64, align 8
|
||||||
|
%uremainder = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
store i64* %remainder, i64** %3, align 4
|
||||||
|
store i32 63, i32* %signbitidx, align 4
|
||||||
|
%4 = load i64* %1, align 8
|
||||||
|
%5 = icmp slt i64 %4, 0
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
store i32 %6, i32* %signed_dividend, align 4
|
||||||
|
%7 = load i64* %2, align 8
|
||||||
|
%8 = icmp slt i64 %7, 0
|
||||||
|
%9 = zext i1 %8 to i32
|
||||||
|
store i32 %9, i32* %signed_divisor, align 4
|
||||||
|
%10 = load i32* %signed_divisor, align 4
|
||||||
|
%11 = load i32* %signed_dividend, align 4
|
||||||
|
%12 = xor i32 %10, %11
|
||||||
|
store i32 %12, i32* %signed_result, align 4
|
||||||
|
%13 = load i32* %signed_dividend, align 4
|
||||||
|
%14 = icmp ne i32 %13, 0
|
||||||
|
br i1 %14, label %15, label %18
|
||||||
|
|
||||||
|
; <label>:15 ; preds = %0
|
||||||
|
%16 = load i64* %1, align 8
|
||||||
|
%17 = sub nsw i64 0, %16
|
||||||
|
br label %20
|
||||||
|
|
||||||
|
; <label>:18 ; preds = %0
|
||||||
|
%19 = load i64* %1, align 8
|
||||||
|
br label %20
|
||||||
|
|
||||||
|
; <label>:20 ; preds = %18, %15
|
||||||
|
%21 = phi i64 [ %17, %15 ], [ %19, %18 ]
|
||||||
|
store i64 %21, i64* %udvd, align 8
|
||||||
|
%22 = load i32* %signed_divisor, align 4
|
||||||
|
%23 = icmp ne i32 %22, 0
|
||||||
|
br i1 %23, label %24, label %27
|
||||||
|
|
||||||
|
; <label>:24 ; preds = %20
|
||||||
|
%25 = load i64* %2, align 8
|
||||||
|
%26 = sub nsw i64 0, %25
|
||||||
|
br label %29
|
||||||
|
|
||||||
|
; <label>:27 ; preds = %20
|
||||||
|
%28 = load i64* %2, align 8
|
||||||
|
br label %29
|
||||||
|
|
||||||
|
; <label>:29 ; preds = %27, %24
|
||||||
|
%30 = phi i64 [ %26, %24 ], [ %28, %27 ]
|
||||||
|
store i64 %30, i64* %udvr, align 8
|
||||||
|
%31 = load i64* %udvd, align 8
|
||||||
|
%32 = load i64* %udvr, align 8
|
||||||
|
%33 = call i64 @udivmod64(i64 %31, i64 %32, i64* %uremainder)
|
||||||
|
store i64 %33, i64* %uquotient, align 8
|
||||||
|
%34 = load i32* %signed_result, align 4
|
||||||
|
%35 = icmp ne i32 %34, 0
|
||||||
|
br i1 %35, label %36, label %57
|
||||||
|
|
||||||
|
; <label>:36 ; preds = %29
|
||||||
|
%37 = load i64* %uremainder, align 8
|
||||||
|
%38 = icmp ne i64 %37, 0
|
||||||
|
br i1 %38, label %39, label %43
|
||||||
|
|
||||||
|
; <label>:39 ; preds = %36
|
||||||
|
%40 = load i64* %uquotient, align 8
|
||||||
|
%41 = sub nsw i64 0, %40
|
||||||
|
%42 = sub nsw i64 %41, 1
|
||||||
|
store i64 %42, i64* %quotient, align 8
|
||||||
|
br label %46
|
||||||
|
|
||||||
|
; <label>:43 ; preds = %36
|
||||||
|
%44 = load i64* %uquotient, align 8
|
||||||
|
%45 = sub nsw i64 0, %44
|
||||||
|
store i64 %45, i64* %quotient, align 8
|
||||||
|
br label %46
|
||||||
|
|
||||||
|
; <label>:46 ; preds = %43, %39
|
||||||
|
%47 = load i64** %3, align 4
|
||||||
|
%48 = icmp ne i64* %47, null
|
||||||
|
br i1 %48, label %49, label %56
|
||||||
|
|
||||||
|
; <label>:49 ; preds = %46
|
||||||
|
%50 = load i64* %1, align 8
|
||||||
|
%51 = load i64* %quotient, align 8
|
||||||
|
%52 = load i64* %2, align 8
|
||||||
|
%53 = mul i64 %51, %52
|
||||||
|
%54 = sub i64 %50, %53
|
||||||
|
%55 = load i64** %3, align 4
|
||||||
|
store i64 %54, i64* %55, align 4
|
||||||
|
br label %56
|
||||||
|
|
||||||
|
; <label>:56 ; preds = %49, %46
|
||||||
|
br label %73
|
||||||
|
|
||||||
|
; <label>:57 ; preds = %29
|
||||||
|
%58 = load i64* %uquotient, align 8
|
||||||
|
store i64 %58, i64* %quotient, align 8
|
||||||
|
%59 = load i64** %3, align 4
|
||||||
|
%60 = icmp ne i64* %59, null
|
||||||
|
br i1 %60, label %61, label %72
|
||||||
|
|
||||||
|
; <label>:61 ; preds = %57
|
||||||
|
%62 = load i32* %signed_divisor, align 4
|
||||||
|
%63 = icmp ne i32 %62, 0
|
||||||
|
br i1 %63, label %64, label %67
|
||||||
|
|
||||||
|
; <label>:64 ; preds = %61
|
||||||
|
%65 = load i64* %uremainder, align 8
|
||||||
|
%66 = sub i64 0, %65
|
||||||
|
br label %69
|
||||||
|
|
||||||
|
; <label>:67 ; preds = %61
|
||||||
|
%68 = load i64* %uremainder, align 8
|
||||||
|
br label %69
|
||||||
|
|
||||||
|
; <label>:69 ; preds = %67, %64
|
||||||
|
%70 = phi i64 [ %66, %64 ], [ %68, %67 ]
|
||||||
|
%71 = load i64** %3, align 4
|
||||||
|
store i64 %70, i64* %71, align 4
|
||||||
|
br label %72
|
||||||
|
|
||||||
|
; <label>:72 ; preds = %69, %57
|
||||||
|
br label %73
|
||||||
|
|
||||||
|
; <label>:73 ; preds = %72, %56
|
||||||
|
%74 = load i64* %quotient, align 8
|
||||||
|
ret i64 %74
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @udiv64(i64 %dividend, i64 %divisor) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @udivmod64(i64 %3, i64 %4, i64* null)
|
||||||
|
ret i64 %5
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @sdiv64(i64 %dividend, i64 %divisor) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @sdivmod64(i64 %3, i64 %4, i64* null)
|
||||||
|
ret i64 %5
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @umod64(i64 %dividend, i64 %divisor) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%rem = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @udivmod64(i64 %3, i64 %4, i64* %rem)
|
||||||
|
%6 = load i64* %rem, align 8
|
||||||
|
ret i64 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @smod64(i64 %dividend, i64 %divisor) nounwind ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%rem = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @sdivmod64(i64 %3, i64 %4, i64* %rem)
|
||||||
|
%6 = load i64* %rem, align 8
|
||||||
|
ret i64 %6
|
||||||
|
}
|
||||||
371
llvm/llrt/llrt_x86_64.ll
Normal file
371
llvm/llrt/llrt_x86_64.ll
Normal file
|
|
@ -0,0 +1,371 @@
|
||||||
|
; ModuleID = 'udivmod64_x86_64.bc'
|
||||||
|
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
|
||||||
|
|
||||||
|
%struct.div_state_ = type { i64, i64 }
|
||||||
|
|
||||||
|
define i64 @udivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%3 = alloca i64, align 8
|
||||||
|
%4 = alloca i64*, align 8
|
||||||
|
%state = alloca %struct.div_state_, align 8
|
||||||
|
%quotient = alloca i64, align 8
|
||||||
|
%i = alloca i32, align 4
|
||||||
|
%skipahead = alloca i32, align 4
|
||||||
|
store i64 %dividend, i64* %2, align 8
|
||||||
|
store i64 %divisor, i64* %3, align 8
|
||||||
|
store i64* %remainder, i64** %4, align 8
|
||||||
|
%5 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
store i64 0, i64* %5, align 8
|
||||||
|
%6 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 1
|
||||||
|
%7 = load i64* %2, align 8
|
||||||
|
store i64 %7, i64* %6, align 8
|
||||||
|
store i64 0, i64* %quotient, align 8
|
||||||
|
%8 = load i64* %3, align 8
|
||||||
|
%9 = icmp eq i64 %8, 0
|
||||||
|
br i1 %9, label %10, label %11
|
||||||
|
|
||||||
|
; <label>:10 ; preds = %0
|
||||||
|
store i64 0, i64* %1
|
||||||
|
br label %57
|
||||||
|
|
||||||
|
; <label>:11 ; preds = %0
|
||||||
|
%12 = load i64* %2, align 8
|
||||||
|
%13 = call i32 @clz64(i64 %12)
|
||||||
|
store i32 %13, i32* %skipahead, align 4
|
||||||
|
store i32 0, i32* %i, align 4
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:14 ; preds = %19, %11
|
||||||
|
%15 = load i32* %i, align 4
|
||||||
|
%16 = load i32* %skipahead, align 4
|
||||||
|
%17 = icmp slt i32 %15, %16
|
||||||
|
br i1 %17, label %18, label %22
|
||||||
|
|
||||||
|
; <label>:18 ; preds = %14
|
||||||
|
call void @div_state_lshift(%struct.div_state_* %state)
|
||||||
|
br label %19
|
||||||
|
|
||||||
|
; <label>:19 ; preds = %18
|
||||||
|
%20 = load i32* %i, align 4
|
||||||
|
%21 = add nsw i32 %20, 1
|
||||||
|
store i32 %21, i32* %i, align 4
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:22 ; preds = %14
|
||||||
|
%23 = load i32* %skipahead, align 4
|
||||||
|
store i32 %23, i32* %i, align 4
|
||||||
|
br label %24
|
||||||
|
|
||||||
|
; <label>:24 ; preds = %45, %22
|
||||||
|
%25 = load i32* %i, align 4
|
||||||
|
%26 = icmp slt i32 %25, 64
|
||||||
|
br i1 %26, label %27, label %48
|
||||||
|
|
||||||
|
; <label>:27 ; preds = %24
|
||||||
|
call void @div_state_lshift(%struct.div_state_* %state)
|
||||||
|
%28 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%29 = load i64* %28, align 8
|
||||||
|
%30 = load i64* %3, align 8
|
||||||
|
%31 = icmp uge i64 %29, %30
|
||||||
|
br i1 %31, label %32, label %44
|
||||||
|
|
||||||
|
; <label>:32 ; preds = %27
|
||||||
|
%33 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%34 = load i64* %33, align 8
|
||||||
|
%35 = load i64* %3, align 8
|
||||||
|
%36 = sub i64 %34, %35
|
||||||
|
%37 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
store i64 %36, i64* %37, align 8
|
||||||
|
%38 = load i32* %i, align 4
|
||||||
|
%39 = sub nsw i32 63, %38
|
||||||
|
%40 = zext i32 %39 to i64
|
||||||
|
%41 = shl i64 1, %40
|
||||||
|
%42 = load i64* %quotient, align 8
|
||||||
|
%43 = or i64 %42, %41
|
||||||
|
store i64 %43, i64* %quotient, align 8
|
||||||
|
br label %44
|
||||||
|
|
||||||
|
; <label>:44 ; preds = %32, %27
|
||||||
|
br label %45
|
||||||
|
|
||||||
|
; <label>:45 ; preds = %44
|
||||||
|
%46 = load i32* %i, align 4
|
||||||
|
%47 = add nsw i32 %46, 1
|
||||||
|
store i32 %47, i32* %i, align 4
|
||||||
|
br label %24
|
||||||
|
|
||||||
|
; <label>:48 ; preds = %24
|
||||||
|
%49 = load i64** %4, align 8
|
||||||
|
%50 = icmp ne i64* %49, null
|
||||||
|
br i1 %50, label %51, label %55
|
||||||
|
|
||||||
|
; <label>:51 ; preds = %48
|
||||||
|
%52 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0
|
||||||
|
%53 = load i64* %52, align 8
|
||||||
|
%54 = load i64** %4, align 8
|
||||||
|
store i64 %53, i64* %54, align 8
|
||||||
|
br label %55
|
||||||
|
|
||||||
|
; <label>:55 ; preds = %51, %48
|
||||||
|
%56 = load i64* %quotient, align 8
|
||||||
|
store i64 %56, i64* %1
|
||||||
|
br label %57
|
||||||
|
|
||||||
|
; <label>:57 ; preds = %55, %10
|
||||||
|
%58 = load i64* %1
|
||||||
|
ret i64 %58
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal i32 @clz64(i64 %x) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%total_bits = alloca i32, align 4
|
||||||
|
%zc = alloca i32, align 4
|
||||||
|
store i64 %x, i64* %1, align 8
|
||||||
|
store i32 64, i32* %total_bits, align 4
|
||||||
|
store i32 0, i32* %zc, align 4
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:2 ; preds = %16, %0
|
||||||
|
%3 = load i32* %zc, align 4
|
||||||
|
%4 = icmp slt i32 %3, 64
|
||||||
|
br i1 %4, label %5, label %14
|
||||||
|
|
||||||
|
; <label>:5 ; preds = %2
|
||||||
|
%6 = load i64* %1, align 8
|
||||||
|
%7 = load i32* %zc, align 4
|
||||||
|
%8 = sub nsw i32 64, %7
|
||||||
|
%9 = sub nsw i32 %8, 1
|
||||||
|
%10 = zext i32 %9 to i64
|
||||||
|
%11 = lshr i64 %6, %10
|
||||||
|
%12 = and i64 %11, 1
|
||||||
|
%13 = icmp eq i64 %12, 0
|
||||||
|
br label %14
|
||||||
|
|
||||||
|
; <label>:14 ; preds = %5, %2
|
||||||
|
%15 = phi i1 [ false, %2 ], [ %13, %5 ]
|
||||||
|
br i1 %15, label %16, label %19
|
||||||
|
|
||||||
|
; <label>:16 ; preds = %14
|
||||||
|
%17 = load i32* %zc, align 4
|
||||||
|
%18 = add nsw i32 %17, 1
|
||||||
|
store i32 %18, i32* %zc, align 4
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:19 ; preds = %14
|
||||||
|
%20 = load i32* %zc, align 4
|
||||||
|
ret i32 %20
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @div_state_lshift(%struct.div_state_* %state) nounwind uwtable ssp {
|
||||||
|
%1 = alloca %struct.div_state_*, align 8
|
||||||
|
store %struct.div_state_* %state, %struct.div_state_** %1, align 8
|
||||||
|
%2 = load %struct.div_state_** %1, align 8
|
||||||
|
%3 = getelementptr inbounds %struct.div_state_* %2, i32 0, i32 0
|
||||||
|
%4 = load i64* %3, align 8
|
||||||
|
%5 = shl i64 %4, 1
|
||||||
|
%6 = load %struct.div_state_** %1, align 8
|
||||||
|
%7 = getelementptr inbounds %struct.div_state_* %6, i32 0, i32 1
|
||||||
|
%8 = load i64* %7, align 8
|
||||||
|
%9 = lshr i64 %8, 63
|
||||||
|
%10 = or i64 %5, %9
|
||||||
|
%11 = load %struct.div_state_** %1, align 8
|
||||||
|
%12 = getelementptr inbounds %struct.div_state_* %11, i32 0, i32 0
|
||||||
|
store i64 %10, i64* %12, align 8
|
||||||
|
%13 = load %struct.div_state_** %1, align 8
|
||||||
|
%14 = getelementptr inbounds %struct.div_state_* %13, i32 0, i32 1
|
||||||
|
%15 = load i64* %14, align 8
|
||||||
|
%16 = shl i64 %15, 1
|
||||||
|
%17 = load %struct.div_state_** %1, align 8
|
||||||
|
%18 = getelementptr inbounds %struct.div_state_* %17, i32 0, i32 1
|
||||||
|
store i64 %16, i64* %18, align 8
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @sdivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%3 = alloca i64*, align 8
|
||||||
|
%signbitidx = alloca i32, align 4
|
||||||
|
%signed_dividend = alloca i32, align 4
|
||||||
|
%signed_divisor = alloca i32, align 4
|
||||||
|
%signed_result = alloca i32, align 4
|
||||||
|
%quotient = alloca i64, align 8
|
||||||
|
%udvd = alloca i64, align 8
|
||||||
|
%udvr = alloca i64, align 8
|
||||||
|
%uquotient = alloca i64, align 8
|
||||||
|
%uremainder = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
store i64* %remainder, i64** %3, align 8
|
||||||
|
store i32 63, i32* %signbitidx, align 4
|
||||||
|
%4 = load i64* %1, align 8
|
||||||
|
%5 = icmp slt i64 %4, 0
|
||||||
|
%6 = zext i1 %5 to i32
|
||||||
|
store i32 %6, i32* %signed_dividend, align 4
|
||||||
|
%7 = load i64* %2, align 8
|
||||||
|
%8 = icmp slt i64 %7, 0
|
||||||
|
%9 = zext i1 %8 to i32
|
||||||
|
store i32 %9, i32* %signed_divisor, align 4
|
||||||
|
%10 = load i32* %signed_divisor, align 4
|
||||||
|
%11 = load i32* %signed_dividend, align 4
|
||||||
|
%12 = xor i32 %10, %11
|
||||||
|
store i32 %12, i32* %signed_result, align 4
|
||||||
|
%13 = load i32* %signed_dividend, align 4
|
||||||
|
%14 = icmp ne i32 %13, 0
|
||||||
|
br i1 %14, label %15, label %18
|
||||||
|
|
||||||
|
; <label>:15 ; preds = %0
|
||||||
|
%16 = load i64* %1, align 8
|
||||||
|
%17 = sub nsw i64 0, %16
|
||||||
|
br label %20
|
||||||
|
|
||||||
|
; <label>:18 ; preds = %0
|
||||||
|
%19 = load i64* %1, align 8
|
||||||
|
br label %20
|
||||||
|
|
||||||
|
; <label>:20 ; preds = %18, %15
|
||||||
|
%21 = phi i64 [ %17, %15 ], [ %19, %18 ]
|
||||||
|
store i64 %21, i64* %udvd, align 8
|
||||||
|
%22 = load i32* %signed_divisor, align 4
|
||||||
|
%23 = icmp ne i32 %22, 0
|
||||||
|
br i1 %23, label %24, label %27
|
||||||
|
|
||||||
|
; <label>:24 ; preds = %20
|
||||||
|
%25 = load i64* %2, align 8
|
||||||
|
%26 = sub nsw i64 0, %25
|
||||||
|
br label %29
|
||||||
|
|
||||||
|
; <label>:27 ; preds = %20
|
||||||
|
%28 = load i64* %2, align 8
|
||||||
|
br label %29
|
||||||
|
|
||||||
|
; <label>:29 ; preds = %27, %24
|
||||||
|
%30 = phi i64 [ %26, %24 ], [ %28, %27 ]
|
||||||
|
store i64 %30, i64* %udvr, align 8
|
||||||
|
%31 = load i64* %udvd, align 8
|
||||||
|
%32 = load i64* %udvr, align 8
|
||||||
|
%33 = call i64 @udivmod64(i64 %31, i64 %32, i64* %uremainder)
|
||||||
|
store i64 %33, i64* %uquotient, align 8
|
||||||
|
%34 = load i32* %signed_result, align 4
|
||||||
|
%35 = icmp ne i32 %34, 0
|
||||||
|
br i1 %35, label %36, label %57
|
||||||
|
|
||||||
|
; <label>:36 ; preds = %29
|
||||||
|
%37 = load i64* %uremainder, align 8
|
||||||
|
%38 = icmp ne i64 %37, 0
|
||||||
|
br i1 %38, label %39, label %43
|
||||||
|
|
||||||
|
; <label>:39 ; preds = %36
|
||||||
|
%40 = load i64* %uquotient, align 8
|
||||||
|
%41 = sub nsw i64 0, %40
|
||||||
|
%42 = sub nsw i64 %41, 1
|
||||||
|
store i64 %42, i64* %quotient, align 8
|
||||||
|
br label %46
|
||||||
|
|
||||||
|
; <label>:43 ; preds = %36
|
||||||
|
%44 = load i64* %uquotient, align 8
|
||||||
|
%45 = sub nsw i64 0, %44
|
||||||
|
store i64 %45, i64* %quotient, align 8
|
||||||
|
br label %46
|
||||||
|
|
||||||
|
; <label>:46 ; preds = %43, %39
|
||||||
|
%47 = load i64** %3, align 8
|
||||||
|
%48 = icmp ne i64* %47, null
|
||||||
|
br i1 %48, label %49, label %56
|
||||||
|
|
||||||
|
; <label>:49 ; preds = %46
|
||||||
|
%50 = load i64* %1, align 8
|
||||||
|
%51 = load i64* %quotient, align 8
|
||||||
|
%52 = load i64* %2, align 8
|
||||||
|
%53 = mul i64 %51, %52
|
||||||
|
%54 = sub i64 %50, %53
|
||||||
|
%55 = load i64** %3, align 8
|
||||||
|
store i64 %54, i64* %55, align 8
|
||||||
|
br label %56
|
||||||
|
|
||||||
|
; <label>:56 ; preds = %49, %46
|
||||||
|
br label %73
|
||||||
|
|
||||||
|
; <label>:57 ; preds = %29
|
||||||
|
%58 = load i64* %uquotient, align 8
|
||||||
|
store i64 %58, i64* %quotient, align 8
|
||||||
|
%59 = load i64** %3, align 8
|
||||||
|
%60 = icmp ne i64* %59, null
|
||||||
|
br i1 %60, label %61, label %72
|
||||||
|
|
||||||
|
; <label>:61 ; preds = %57
|
||||||
|
%62 = load i32* %signed_divisor, align 4
|
||||||
|
%63 = icmp ne i32 %62, 0
|
||||||
|
br i1 %63, label %64, label %67
|
||||||
|
|
||||||
|
; <label>:64 ; preds = %61
|
||||||
|
%65 = load i64* %uremainder, align 8
|
||||||
|
%66 = sub i64 0, %65
|
||||||
|
br label %69
|
||||||
|
|
||||||
|
; <label>:67 ; preds = %61
|
||||||
|
%68 = load i64* %uremainder, align 8
|
||||||
|
br label %69
|
||||||
|
|
||||||
|
; <label>:69 ; preds = %67, %64
|
||||||
|
%70 = phi i64 [ %66, %64 ], [ %68, %67 ]
|
||||||
|
%71 = load i64** %3, align 8
|
||||||
|
store i64 %70, i64* %71, align 8
|
||||||
|
br label %72
|
||||||
|
|
||||||
|
; <label>:72 ; preds = %69, %57
|
||||||
|
br label %73
|
||||||
|
|
||||||
|
; <label>:73 ; preds = %72, %56
|
||||||
|
%74 = load i64* %quotient, align 8
|
||||||
|
ret i64 %74
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @udiv64(i64 %dividend, i64 %divisor) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @udivmod64(i64 %3, i64 %4, i64* null)
|
||||||
|
ret i64 %5
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @sdiv64(i64 %dividend, i64 %divisor) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @sdivmod64(i64 %3, i64 %4, i64* null)
|
||||||
|
ret i64 %5
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @umod64(i64 %dividend, i64 %divisor) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%rem = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @udivmod64(i64 %3, i64 %4, i64* %rem)
|
||||||
|
%6 = load i64* %rem, align 8
|
||||||
|
ret i64 %6
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @smod64(i64 %dividend, i64 %divisor) nounwind uwtable ssp {
|
||||||
|
%1 = alloca i64, align 8
|
||||||
|
%2 = alloca i64, align 8
|
||||||
|
%rem = alloca i64, align 8
|
||||||
|
store i64 %dividend, i64* %1, align 8
|
||||||
|
store i64 %divisor, i64* %2, align 8
|
||||||
|
%3 = load i64* %1, align 8
|
||||||
|
%4 = load i64* %2, align 8
|
||||||
|
%5 = call i64 @sdivmod64(i64 %3, i64 %4, i64* %rem)
|
||||||
|
%6 = load i64* %rem, align 8
|
||||||
|
ret i64 %6
|
||||||
|
}
|
||||||
242
llvm/mc/__init__.py
Normal file
242
llvm/mc/__init__.py
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import llvm
|
||||||
|
if llvm.version < (3, 4):
|
||||||
|
raise Exception("mc is not supported for llvm version less than 3.4")
|
||||||
|
|
||||||
|
from io import BytesIO
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from llvmpy import api, extra
|
||||||
|
from llvmpy.api.llvm import MCDisassembler
|
||||||
|
|
||||||
|
class Operand(object):
|
||||||
|
|
||||||
|
def __init__(self, mcoperand, target_machine):
|
||||||
|
'''
|
||||||
|
@mcoperand: an MCOperand object
|
||||||
|
@target_machine: an llvm.target.TargetMachine object
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.op = mcoperand
|
||||||
|
if not self.op:
|
||||||
|
raise llvm.LLVMException("null MCOperand argument")
|
||||||
|
|
||||||
|
self.tm = target_machine
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "invalid"
|
||||||
|
if self.is_reg():
|
||||||
|
s = "reg(%s)" % (self.reg_name())
|
||||||
|
elif self.is_imm():
|
||||||
|
s = "imm(0x%02x)" % (self.op.getImm())
|
||||||
|
elif self.is_fp_imm():
|
||||||
|
s = "imm(%r)" % (self.op.getFPImm())
|
||||||
|
elif self.is_expr():
|
||||||
|
s = "expr(%r)" % (self.op.getExpr().getKind())
|
||||||
|
elif self.is_inst():
|
||||||
|
s = repr(Instr(self.op.getInst()))
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def reg_name(self):
|
||||||
|
if self.is_reg():
|
||||||
|
s = self.tm.reg_info.getName(self.op.getReg())
|
||||||
|
if s.strip() == "":
|
||||||
|
return "?"
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def is_reg(self):
|
||||||
|
return self.op.isReg()
|
||||||
|
|
||||||
|
def is_imm(self):
|
||||||
|
return self.op.isImm()
|
||||||
|
|
||||||
|
def is_fp_imm(self):
|
||||||
|
return self.op.isFPImm()
|
||||||
|
|
||||||
|
def is_expr(self):
|
||||||
|
return self.op.isExpr()
|
||||||
|
|
||||||
|
def is_inst(self):
|
||||||
|
return self.op.isInst()
|
||||||
|
|
||||||
|
def get_imm(self):
|
||||||
|
if self.is_imm():
|
||||||
|
return self.op.getImm()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_fp_imm(self):
|
||||||
|
if self.is_fp_imm():
|
||||||
|
return self.op.getFPImm()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_inst(self):
|
||||||
|
if self.is_inst():
|
||||||
|
return Instr(self.op.getInst())
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
class Instr(object):
|
||||||
|
|
||||||
|
def __init__(self, mcinst, target_machine):
|
||||||
|
'''
|
||||||
|
@mcinst: an MCInst object
|
||||||
|
@target_machine: an llvm.target.TargetMachine object
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.mcinst = mcinst
|
||||||
|
if not self.mcinst:
|
||||||
|
raise llvm.LLVMException("null MCInst argument")
|
||||||
|
|
||||||
|
self.tm = target_machine
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
os = extra.make_raw_ostream_for_printing()
|
||||||
|
self.tm.inst_printer.printInst(self.mcinst, os, "")
|
||||||
|
return str(os.str())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
''' the number of operands '''
|
||||||
|
return int(self.mcinst.size())
|
||||||
|
|
||||||
|
def operands(self):
|
||||||
|
amt = self.mcinst.getNumOperands()
|
||||||
|
if amt < 1:
|
||||||
|
return []
|
||||||
|
|
||||||
|
l = []
|
||||||
|
for i in range(0, amt):
|
||||||
|
l.append(Operand(self.mcinst.getOperand(i), self.tm))
|
||||||
|
|
||||||
|
return l
|
||||||
|
|
||||||
|
@property
|
||||||
|
def instr_desc(self):
|
||||||
|
return self.tm.instr_info.get(self.opcode)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flags(self):
|
||||||
|
return self.instr_desc.getFlags()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ts_flags(self):
|
||||||
|
return self.instr_desc.TSFlags
|
||||||
|
|
||||||
|
@property
|
||||||
|
def opcode(self):
|
||||||
|
return self.mcinst.getOpcode()
|
||||||
|
|
||||||
|
def is_branch(self):
|
||||||
|
return self.instr_desc.isBranch()
|
||||||
|
|
||||||
|
def is_cond_branch(self):
|
||||||
|
return self.instr_desc.isConditionalBranch()
|
||||||
|
|
||||||
|
def is_uncond_branch(self):
|
||||||
|
return self.instr_desc.isUnconditionalBranch()
|
||||||
|
|
||||||
|
def is_indirect_branch(self):
|
||||||
|
return self.instr_desc.isIndirectBranch()
|
||||||
|
|
||||||
|
def is_call(self):
|
||||||
|
return self.instr_desc.isCall()
|
||||||
|
|
||||||
|
def is_return(self):
|
||||||
|
return self.instr_desc.isReturn()
|
||||||
|
|
||||||
|
def is_terminator(self):
|
||||||
|
return self.instr_desc.isTerminator()
|
||||||
|
|
||||||
|
def is_barrier(self):
|
||||||
|
return self.instr_desc.isBarrier()
|
||||||
|
|
||||||
|
class BadInstr(Instr):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Disassembler(object):
|
||||||
|
|
||||||
|
def __init__(self, target_machine):
|
||||||
|
self.tm = target_machine
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mdasm(self):
|
||||||
|
return self.tm.disassembler
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mai(self):
|
||||||
|
return self.tm.asm_info
|
||||||
|
|
||||||
|
def instr(self, mcinst):
|
||||||
|
return Instr(mcinst, self.tm)
|
||||||
|
|
||||||
|
def bad_instr(self, mcinst):
|
||||||
|
return BadInstr(mcinst, self.tm)
|
||||||
|
|
||||||
|
def decode(self, bs, base_addr, align=None):
|
||||||
|
'''
|
||||||
|
decodes the bytes in @bs into instructions and yields
|
||||||
|
each instruction as it is decoded. @base_addr is the base address
|
||||||
|
where the instruction bytes are from (not an offset into
|
||||||
|
@bs). yields instructions in the form of (addr, data, inst) where
|
||||||
|
addr is an integer, data is a tuple of integers and inst is an instance of
|
||||||
|
llvm.mc.Instr. @align specifies the byte alignment of instructions and
|
||||||
|
is only used if an un-decodable instruction is encountered, in which
|
||||||
|
case the disassembler will skip the following bytes until the next
|
||||||
|
aligned address. if @align is unspecified, the default alignment
|
||||||
|
for the architecture will be used, however this may not be ideal
|
||||||
|
for disassembly. for example, the default alignment for ARM is 1, but you
|
||||||
|
probably want it to be 4 for the purposes of disassembling ARM
|
||||||
|
instructions.
|
||||||
|
'''
|
||||||
|
|
||||||
|
if isinstance(bs, str) and sys.version_info.major >= 3:
|
||||||
|
bs = bytes(map(lambda c: ord(c), bs))
|
||||||
|
elif not isinstance(bs, bytes):
|
||||||
|
raise TypeError("expected bs to be either 'str' or 'bytes' but got %s" % type(bs))
|
||||||
|
|
||||||
|
code = api.llvm.StringRefMemoryObject.new(bs, base_addr)
|
||||||
|
idx = 0
|
||||||
|
if not isinstance(align, int) or align < 1:
|
||||||
|
align = self.mai.getMinInstAlignment()
|
||||||
|
|
||||||
|
while(idx < code.getExtent()):
|
||||||
|
inst = api.llvm.MCInst.new()
|
||||||
|
addr = code.getBase() + idx
|
||||||
|
status, size = self.mdasm.getInstruction(inst, code, addr)
|
||||||
|
|
||||||
|
if size < 1:
|
||||||
|
size = (align - (idx % align))
|
||||||
|
|
||||||
|
amt_left = code.getExtent() - idx
|
||||||
|
if amt_left >= size:
|
||||||
|
data = code.readBytes(addr, size)
|
||||||
|
elif amt_left < 1:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
data = code.readBytes(addr, amt_left)
|
||||||
|
|
||||||
|
if sys.version_info.major < 3:
|
||||||
|
data = tuple(map(lambda b: ord(b), data))
|
||||||
|
else:
|
||||||
|
data = tuple(data)
|
||||||
|
|
||||||
|
if status == MCDisassembler.DecodeStatus.Fail:
|
||||||
|
yield (addr, data, None)
|
||||||
|
elif status == MCDisassembler.DecodeStatus.SoftFail:
|
||||||
|
yield (addr, data, self.bad_instr(inst))
|
||||||
|
else:
|
||||||
|
yield (addr, data, self.instr(inst))
|
||||||
|
|
||||||
|
idx += size
|
||||||
|
|
@ -70,13 +70,33 @@ class PassManagerBuilder(llvm.Wrapper):
|
||||||
def size_level(self, sizelevel):
|
def size_level(self, sizelevel):
|
||||||
self._ptr.SizeLevel = sizelevel
|
self._ptr.SizeLevel = sizelevel
|
||||||
|
|
||||||
@property
|
if llvm.version >= (3, 3):
|
||||||
def vectorize(self):
|
@property
|
||||||
return self._ptr.Vectorize
|
def bbvectorize(self):
|
||||||
|
return self._ptr.BBVectorize
|
||||||
|
|
||||||
@vectorize.setter
|
@bbvectorize.setter
|
||||||
def vectorize(self, enable):
|
def bbvectorize(self, enable):
|
||||||
self._ptr.Vectorize = enable
|
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):
|
||||||
|
return self._ptr.Vectorize
|
||||||
|
|
||||||
|
@vectorize.setter
|
||||||
|
def vectorize(self, enable):
|
||||||
|
self._ptr.Vectorize = enable
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -109,13 +129,14 @@ class PassManagerBuilder(llvm.Wrapper):
|
||||||
def disable_unroll_loops(self, disable):
|
def disable_unroll_loops(self, disable):
|
||||||
self._ptr.DisableUnrollLoops = disable
|
self._ptr.DisableUnrollLoops = disable
|
||||||
|
|
||||||
@property
|
if llvm.version <= (3, 3):
|
||||||
def disable_simplify_lib_calls(self):
|
@property
|
||||||
return self._ptr.DisableSimplifyLibCalls
|
def disable_simplify_lib_calls(self):
|
||||||
|
return self._ptr.DisableSimplifyLibCalls
|
||||||
|
|
||||||
@disable_simplify_lib_calls.setter
|
@disable_simplify_lib_calls.setter
|
||||||
def disable_simplify_lib_calls(self, disable):
|
def disable_simplify_lib_calls(self, disable):
|
||||||
self._ptr.DisableSimplifyLibCalls = disable
|
self._ptr.DisableSimplifyLibCalls = disable
|
||||||
|
|
||||||
def use_inliner_with_threshold(self, threshold):
|
def use_inliner_with_threshold(self, threshold):
|
||||||
self._ptr.Inliner = api.llvm.createFunctionInliningPass(threshold)
|
self._ptr.Inliner = api.llvm.createFunctionInliningPass(threshold)
|
||||||
|
|
@ -299,13 +320,15 @@ class TargetTransformInfo(Pass):
|
||||||
# Helpers
|
# Helpers
|
||||||
#===----------------------------------------------------------------------===
|
#===----------------------------------------------------------------------===
|
||||||
|
|
||||||
def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False,
|
def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False,
|
||||||
inline_threshold=2000, pm=True, fpm=True, mod=None):
|
slp_vectorize=False, vectorize=False,
|
||||||
|
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.
|
||||||
|
|
@ -314,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.
|
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:
|
||||||
|
|
@ -326,22 +361,27 @@ def build_pass_managers(tm, opt=2, loop_vectorize=False, 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)
|
||||||
|
|
|
||||||
266
llvm/target.py
Normal file
266
llvm/target.py
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
import llvm
|
||||||
|
from llvmpy import api, extra
|
||||||
|
from io import BytesIO
|
||||||
|
import contextlib
|
||||||
|
from llvm.passes import TargetData
|
||||||
|
|
||||||
|
#===----------------------------------------------------------------------===
|
||||||
|
# Enumerations
|
||||||
|
#===----------------------------------------------------------------------===
|
||||||
|
|
||||||
|
BO_BIG_ENDIAN = 0
|
||||||
|
BO_LITTLE_ENDIAN = 1
|
||||||
|
|
||||||
|
# CodeModel
|
||||||
|
CM_DEFAULT = api.llvm.CodeModel.Model.Default
|
||||||
|
CM_JITDEFAULT = api.llvm.CodeModel.Model.JITDefault
|
||||||
|
CM_SMALL = api.llvm.CodeModel.Model.Small
|
||||||
|
CM_KERNEL = api.llvm.CodeModel.Model.Kernel
|
||||||
|
CM_MEDIUM = api.llvm.CodeModel.Model.Medium
|
||||||
|
CM_LARGE = api.llvm.CodeModel.Model.Large
|
||||||
|
|
||||||
|
# Reloc
|
||||||
|
RELOC_DEFAULT = api.llvm.Reloc.Model.Default
|
||||||
|
RELOC_STATIC = api.llvm.Reloc.Model.Static
|
||||||
|
RELOC_PIC = api.llvm.Reloc.Model.PIC_
|
||||||
|
RELOC_DYNAMIC_NO_PIC = api.llvm.Reloc.Model.DynamicNoPIC
|
||||||
|
|
||||||
|
def initialize_all():
|
||||||
|
api.llvm.InitializeAllTargets()
|
||||||
|
api.llvm.InitializeAllTargetInfos()
|
||||||
|
api.llvm.InitializeAllTargetMCs()
|
||||||
|
api.llvm.InitializeAllAsmPrinters()
|
||||||
|
api.llvm.InitializeAllDisassemblers()
|
||||||
|
api.llvm.InitializeAllAsmParsers()
|
||||||
|
|
||||||
|
def initialize_target(target, noraise=False):
|
||||||
|
"""Initialize target by name.
|
||||||
|
It is safe to initialize the same target multiple times.
|
||||||
|
"""
|
||||||
|
prefix = 'LLVMInitialize'
|
||||||
|
postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter', 'AsmParser']
|
||||||
|
try:
|
||||||
|
for postfix in postfixes:
|
||||||
|
getattr(api, '%s%s%s' % (prefix, target, postfix))()
|
||||||
|
except AttributeError:
|
||||||
|
if noraise:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def print_registered_targets():
|
||||||
|
'''
|
||||||
|
Note: print directly to stdout
|
||||||
|
'''
|
||||||
|
api.llvm.TargetRegistry.printRegisteredTargetsForVersion()
|
||||||
|
|
||||||
|
def get_host_cpu_name():
|
||||||
|
'''return the string name of the host CPU
|
||||||
|
'''
|
||||||
|
return api.llvm.sys.getHostCPUName()
|
||||||
|
|
||||||
|
def get_default_triple():
|
||||||
|
'''return the target triple of the host in str-rep
|
||||||
|
'''
|
||||||
|
return api.llvm.sys.getDefaultTargetTriple()
|
||||||
|
|
||||||
|
class TargetMachine(llvm.Wrapper):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT,
|
||||||
|
reloc=RELOC_DEFAULT):
|
||||||
|
if not triple:
|
||||||
|
triple = get_default_triple()
|
||||||
|
if not cpu:
|
||||||
|
cpu = get_host_cpu_name()
|
||||||
|
with contextlib.closing(BytesIO()) as error:
|
||||||
|
target = api.llvm.TargetRegistry.lookupTarget(triple, error)
|
||||||
|
if not target:
|
||||||
|
raise llvm.LLVMException(error.getvalue())
|
||||||
|
if not target.hasTargetMachine():
|
||||||
|
raise llvm.LLVMException(target, "No target machine.")
|
||||||
|
target_options = api.llvm.TargetOptions.new()
|
||||||
|
tm = target.createTargetMachine(triple, cpu, features,
|
||||||
|
target_options,
|
||||||
|
reloc, cm, opt)
|
||||||
|
if not tm:
|
||||||
|
raise llvm.LLVMException("Cannot create target machine")
|
||||||
|
return TargetMachine(tm)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT,
|
||||||
|
reloc=RELOC_DEFAULT):
|
||||||
|
'''create a targetmachine given an architecture name
|
||||||
|
|
||||||
|
For a list of architectures,
|
||||||
|
use: `llc -help`
|
||||||
|
|
||||||
|
For a list of available CPUs,
|
||||||
|
use: `llvm-as < /dev/null | llc -march=xyz -mcpu=help`
|
||||||
|
|
||||||
|
For a list of available attributes (features),
|
||||||
|
use: `llvm-as < /dev/null | llc -march=xyz -mattr=help`
|
||||||
|
'''
|
||||||
|
triple = api.llvm.Triple.new()
|
||||||
|
with contextlib.closing(BytesIO()) as error:
|
||||||
|
target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error)
|
||||||
|
if not target:
|
||||||
|
raise llvm.LLVMException(error.getvalue())
|
||||||
|
if not target.hasTargetMachine():
|
||||||
|
raise llvm.LLVMException(target, "No target machine.")
|
||||||
|
target_options = api.llvm.TargetOptions.new()
|
||||||
|
tm = target.createTargetMachine(str(triple), cpu, features,
|
||||||
|
target_options,
|
||||||
|
reloc, cm, opt)
|
||||||
|
if not tm:
|
||||||
|
raise llvm.LLVMException("Cannot create target machine")
|
||||||
|
return TargetMachine(tm)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def x86():
|
||||||
|
return TargetMachine.lookup('x86')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def x86_64():
|
||||||
|
return TargetMachine.lookup('x86-64')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def arm():
|
||||||
|
return TargetMachine.lookup('arm')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def thumb():
|
||||||
|
return TargetMachine.lookup('thumb')
|
||||||
|
|
||||||
|
def _emit_file(self, module, cgft):
|
||||||
|
pm = api.llvm.PassManager.new()
|
||||||
|
os = extra.make_raw_ostream_for_printing()
|
||||||
|
pm.add(api.llvm.DataLayout.new(str(self.target_data)))
|
||||||
|
failed = self._ptr.addPassesToEmitFile(pm, os, cgft)
|
||||||
|
pm.run(module)
|
||||||
|
|
||||||
|
|
||||||
|
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
||||||
|
if cgft == CGFT.CGFT_ObjectFile:
|
||||||
|
return os.bytes()
|
||||||
|
else:
|
||||||
|
return os.str()
|
||||||
|
|
||||||
|
def emit_assembly(self, module):
|
||||||
|
'''returns byte string of the module as assembly code of the target machine
|
||||||
|
'''
|
||||||
|
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
||||||
|
return self._emit_file(module._ptr, CGFT.CGFT_AssemblyFile)
|
||||||
|
|
||||||
|
def emit_object(self, module):
|
||||||
|
'''returns byte string of the module as native code of the target machine
|
||||||
|
'''
|
||||||
|
CGFT = api.llvm.TargetMachine.CodeGenFileType
|
||||||
|
return self._emit_file(module._ptr, CGFT.CGFT_ObjectFile)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_data(self):
|
||||||
|
'''get target data of this machine
|
||||||
|
'''
|
||||||
|
return TargetData(self._ptr.getDataLayout())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_name(self):
|
||||||
|
return self._ptr.getTarget().getName()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_short_description(self):
|
||||||
|
return self._ptr.getTarget().getShortDescription()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def triple(self):
|
||||||
|
return self._ptr.getTargetTriple()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cpu(self):
|
||||||
|
return self._ptr.getTargetCPU()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def feature_string(self):
|
||||||
|
return self._ptr.getTargetFeatureString()
|
||||||
|
|
||||||
|
@property
|
||||||
|
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):
|
||||||
|
mri = self._ptr.getRegisterInfo()
|
||||||
|
if not mri:
|
||||||
|
raise llvm.LLVMException("no reg info for this machine")
|
||||||
|
|
||||||
|
return mri
|
||||||
|
|
||||||
|
@property
|
||||||
|
def subtarget_info(self):
|
||||||
|
sti = self._ptr.getSubtargetImpl()
|
||||||
|
if not sti:
|
||||||
|
raise llvm.LLVMException("no subtarget info for this machine")
|
||||||
|
|
||||||
|
return sti
|
||||||
|
|
||||||
|
@property
|
||||||
|
def asm_info(self):
|
||||||
|
ai = self._ptr.getMCAsmInfo()
|
||||||
|
if not ai:
|
||||||
|
raise llvm.LLVMException("no asm info for this machine")
|
||||||
|
|
||||||
|
return ai
|
||||||
|
|
||||||
|
@property
|
||||||
|
def instr_info(self):
|
||||||
|
ii = self._ptr.getInstrInfo()
|
||||||
|
if not ii:
|
||||||
|
raise llvm.LLVMException("no instr info for this machine")
|
||||||
|
|
||||||
|
return ii
|
||||||
|
|
||||||
|
@property
|
||||||
|
def instr_analysis(self):
|
||||||
|
if not getattr(self, '_mia', False):
|
||||||
|
self._mia = self.target.createMCInstrAnalysis(self.instr_info)
|
||||||
|
if not self._mia:
|
||||||
|
raise llvm.LLVMException("no instr analysis for this machine")
|
||||||
|
|
||||||
|
return self._mia
|
||||||
|
|
||||||
|
@property
|
||||||
|
def disassembler(self):
|
||||||
|
if not getattr(self, '_dasm', False):
|
||||||
|
self._dasm = self.target.createMCDisassembler(self.subtarget_info)
|
||||||
|
if not self._dasm:
|
||||||
|
raise llvm.LLVMException("no disassembler for this machine")
|
||||||
|
|
||||||
|
return self._dasm
|
||||||
|
|
||||||
|
@property
|
||||||
|
def inst_printer(self):
|
||||||
|
if not getattr(self, '_mip', False):
|
||||||
|
self._mip = self.target.createMCInstPrinter(
|
||||||
|
self.asm_info.getAssemblerDialect(),
|
||||||
|
self.asm_info,
|
||||||
|
self.instr_info,
|
||||||
|
self.reg_info,
|
||||||
|
self.subtarget_info
|
||||||
|
)
|
||||||
|
if not self._mip:
|
||||||
|
raise llvm.LLVMException("no instr printer for this machine")
|
||||||
|
|
||||||
|
return self._mip
|
||||||
|
|
||||||
|
def is_little_endian(self):
|
||||||
|
return self.asm_info.isLittleEndian()
|
||||||
|
|
||||||
1279
llvm/test_llvmpy.py
1279
llvm/test_llvmpy.py
File diff suppressed because it is too large
Load diff
72
llvm/tests/__init__.py
Normal file
72
llvm/tests/__init__.py
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import subprocess
|
||||||
|
import llvm
|
||||||
|
|
||||||
|
tests = [] # stores unittest.TestCase objects
|
||||||
|
|
||||||
|
# Isolated tests
|
||||||
|
# Tests that affect process-wide settings
|
||||||
|
isolated_tests = [] # stores modue name
|
||||||
|
|
||||||
|
|
||||||
|
def run(verbosity=1, run_isolated=True):
|
||||||
|
print('llvmpy is installed in: ' + os.path.dirname(__file__))
|
||||||
|
print('llvmpy version: ' + llvm.__version__)
|
||||||
|
print(sys.version)
|
||||||
|
|
||||||
|
files = filter(lambda s: s.startswith('test_') and s.endswith('.py'),
|
||||||
|
os.listdir(os.path.dirname(__file__)))
|
||||||
|
|
||||||
|
for f in files:
|
||||||
|
fname = f.split('.', 1)[0]
|
||||||
|
__import__('.'.join([__name__, fname]))
|
||||||
|
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
for cls in tests:
|
||||||
|
if cls:
|
||||||
|
suite.addTest(unittest.makeSuite(cls))
|
||||||
|
|
||||||
|
# The default stream fails in IPython qtconsole on Windows,
|
||||||
|
# so just using sys.stdout
|
||||||
|
|
||||||
|
kwargs = dict(verbosity=verbosity, stream=sys.stdout)
|
||||||
|
|
||||||
|
if sys.version_info[:2] > (2, 6):
|
||||||
|
kwargs['buffer'] = True
|
||||||
|
runner = unittest.TextTestRunner(**kwargs)
|
||||||
|
|
||||||
|
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.decode('utf8'), end='')
|
||||||
|
p.wait()
|
||||||
|
if p.returncode:
|
||||||
|
raise Exception("%s returned: %d" % (test, p.returncode))
|
||||||
|
|
||||||
|
return testresult
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
78
llvm/tests/support.py
Normal file
78
llvm/tests/support.py
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
from __future__ import print_function, division
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import unittest
|
||||||
|
import contextlib
|
||||||
|
import types
|
||||||
|
from llvm.tests import tests, isolated_tests # re-expose symbol
|
||||||
|
|
||||||
|
IS_PY3K = sys.version_info[0] >= 3
|
||||||
|
BITS = tuple.__itemsize__ * 8
|
||||||
|
OS = sys.platform
|
||||||
|
MACHINE = platform.machine()
|
||||||
|
INTEL_CPUS = 'i386', 'x86_64'
|
||||||
|
|
||||||
|
if sys.version_info[:2] <= (2, 6):
|
||||||
|
# create custom TestCase
|
||||||
|
class _TestCase(unittest.TestCase):
|
||||||
|
def assertIn(self, item, container):
|
||||||
|
self.assertTrue(item in container)
|
||||||
|
|
||||||
|
def assertNotIn(self, item, container):
|
||||||
|
self.assertFalse(item in container)
|
||||||
|
|
||||||
|
def assertLess(self, a, b):
|
||||||
|
self.assertTrue(a < b)
|
||||||
|
|
||||||
|
def assertIs(self, a, b):
|
||||||
|
self.assertTrue(a is b)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def assertRaises(self, exc):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except exc:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise self.failureException("Did not raise %s" % exc)
|
||||||
|
|
||||||
|
else:
|
||||||
|
_TestCase = unittest.TestCase
|
||||||
|
|
||||||
|
class TestCase(_TestCase):
|
||||||
|
def assertClose(self, got, expect):
|
||||||
|
rel = abs(got - expect) / expect
|
||||||
|
self.assertTrue(rel < 1e-6, 'relative error = %f' % rel)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Tests decorators
|
||||||
|
|
||||||
|
def _skipped(name, msg):
|
||||||
|
def _test(self):
|
||||||
|
if hasattr(unittest, 'SkipTest'):
|
||||||
|
raise unittest.SkipTest(msg)
|
||||||
|
else:
|
||||||
|
print('skipped %s' % name, msg)
|
||||||
|
return _test
|
||||||
|
|
||||||
|
def skip_if(cond, msg=''):
|
||||||
|
def skipper(test):
|
||||||
|
if not isinstance(test, types.FunctionType):
|
||||||
|
repl = None
|
||||||
|
else:
|
||||||
|
repl = _skipped(test, msg)
|
||||||
|
return repl if cond else test
|
||||||
|
return skipper
|
||||||
|
|
||||||
|
skip_if_not_64bits = skip_if(BITS != 64, msg='skipped not 64-bit')
|
||||||
|
|
||||||
|
skip_if_not_32bits = skip_if(BITS != 32, msg='skipped not 32-bits')
|
||||||
|
|
||||||
|
skip_if_win32 = skip_if(OS.startswith('win32'), msg='skipped win32')
|
||||||
|
|
||||||
|
skip_if_not_win32 = skip_if(not OS.startswith('win32'),
|
||||||
|
msg='skipped not win32')
|
||||||
|
skip_if_not_intel_cpu = skip_if(MACHINE not in INTEL_CPUS,
|
||||||
|
msg='skipped not Intel CPU')
|
||||||
|
|
||||||
|
|
||||||
24
llvm/tests/test_alloca.py
Normal file
24
llvm/tests/test_alloca.py
Normal 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()
|
||||||
|
|
||||||
24
llvm/tests/test_arg_attr.py
Normal file
24
llvm/tests/test_arg_attr.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type
|
||||||
|
import llvm.core as lc
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestArgAttr(TestCase):
|
||||||
|
def test_arg_attr(self):
|
||||||
|
m = Module.new('oifjda')
|
||||||
|
vptr = Type.pointer(Type.float())
|
||||||
|
fnty = Type.function(Type.void(), [vptr] * 5)
|
||||||
|
func = m.add_function(fnty, 'foo')
|
||||||
|
attrs = [lc.ATTR_STRUCT_RET, lc.ATTR_BY_VAL, lc.ATTR_NEST,
|
||||||
|
lc.ATTR_NO_ALIAS, lc.ATTR_NO_CAPTURE]
|
||||||
|
for i, attr in enumerate(attrs):
|
||||||
|
arg = func.args[i]
|
||||||
|
self.assertEqual(i, arg.arg_no)
|
||||||
|
arg.add_attribute(attr)
|
||||||
|
self.assertTrue(attr in func.args[i])
|
||||||
|
|
||||||
|
tests.append(TestArgAttr)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
73
llvm/tests/test_arith.py
Normal file
73
llvm/tests/test_arith.py
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import unittest
|
||||||
|
import llvm
|
||||||
|
from llvm.core import (Module, Type, Builder)
|
||||||
|
from llvm.ee import EngineBuilder
|
||||||
|
from .support import TestCase, tests, skip_if, skip_if_not_64bits
|
||||||
|
|
||||||
|
@skip_if(llvm.version < (3, 3))
|
||||||
|
class TestArith(TestCase):
|
||||||
|
'''
|
||||||
|
Test basic arithmetic support with LLVM MCJIT
|
||||||
|
'''
|
||||||
|
def func_template(self, ty, op):
|
||||||
|
m = Module.new('dofjaa')
|
||||||
|
fnty = Type.function(ty, [ty, ty])
|
||||||
|
fn = m.add_function(fnty, 'foo')
|
||||||
|
bldr = Builder.new(fn.append_basic_block(''))
|
||||||
|
bldr.ret(getattr(bldr, op)(*fn.args))
|
||||||
|
|
||||||
|
engine = EngineBuilder.new(m).mcjit(True).create()
|
||||||
|
ptr = engine.get_pointer_to_function(fn)
|
||||||
|
|
||||||
|
from ctypes import c_uint32, c_uint64, c_float, c_double, CFUNCTYPE
|
||||||
|
|
||||||
|
maptypes = {
|
||||||
|
Type.int(32): c_uint32,
|
||||||
|
Type.int(64): c_uint64,
|
||||||
|
Type.float(): c_float,
|
||||||
|
Type.double(): c_double,
|
||||||
|
}
|
||||||
|
cty = maptypes[ty]
|
||||||
|
prototype = CFUNCTYPE(*[cty] * 3)
|
||||||
|
callee = prototype(ptr)
|
||||||
|
callee(12, 23)
|
||||||
|
|
||||||
|
def template(self, iop, fop):
|
||||||
|
inttys = [Type.int(32), Type.int(64)]
|
||||||
|
flttys = [Type.float(), Type.double()]
|
||||||
|
|
||||||
|
if iop:
|
||||||
|
for ty in inttys:
|
||||||
|
self.func_template(ty, iop)
|
||||||
|
if fop:
|
||||||
|
for ty in flttys:
|
||||||
|
self.func_template(ty, fop)
|
||||||
|
|
||||||
|
def test_add(self):
|
||||||
|
self.template('add', 'fadd')
|
||||||
|
|
||||||
|
def test_sub(self):
|
||||||
|
self.template('sub', 'fsub')
|
||||||
|
|
||||||
|
def test_mul(self):
|
||||||
|
self.template('mul', 'fmul')
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_div(self):
|
||||||
|
'''
|
||||||
|
known failure due to unresolved external symbol __udivdi3
|
||||||
|
'''
|
||||||
|
self.template('udiv', None) # 'fdiv')
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_rem(self):
|
||||||
|
'''
|
||||||
|
known failure due to unresolved external symbol __umoddi3
|
||||||
|
'''
|
||||||
|
self.template('urem', None) # 'frem')
|
||||||
|
|
||||||
|
tests.append(TestArith)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
58
llvm/tests/test_asm.py
Normal file
58
llvm/tests/test_asm.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
from llvm.core import Module, Type
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestAsm(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.tmpdir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.tmpdir)
|
||||||
|
|
||||||
|
def test_asm(self):
|
||||||
|
# create a module
|
||||||
|
m = Module.new('module1')
|
||||||
|
m.add_global_variable(Type.int(), 'i')
|
||||||
|
|
||||||
|
# write it's assembly representation to a file
|
||||||
|
asm = str(m)
|
||||||
|
|
||||||
|
testasm_ll = os.path.join(self.tmpdir, 'testasm.ll')
|
||||||
|
with open(testasm_ll, "w") as fout:
|
||||||
|
fout.write(asm)
|
||||||
|
|
||||||
|
# read it back into a module
|
||||||
|
with open(testasm_ll) as fin:
|
||||||
|
m2 = Module.from_assembly(fin)
|
||||||
|
# The default `m.id` is '<string>'.
|
||||||
|
m2.id = m.id # Copy the name from `m`
|
||||||
|
|
||||||
|
self.assertEqual(str(m2).strip(), asm.strip())
|
||||||
|
|
||||||
|
def test_bitcode(self):
|
||||||
|
# create a module
|
||||||
|
m = Module.new('module1')
|
||||||
|
m.add_global_variable(Type.int(), 'i')
|
||||||
|
|
||||||
|
# write it's assembly representation to a file
|
||||||
|
asm = str(m)
|
||||||
|
|
||||||
|
testasm_bc = os.path.join(self.tmpdir, 'testasm.bc')
|
||||||
|
with open(testasm_bc, "wb") as fout:
|
||||||
|
m.to_bitcode(fout)
|
||||||
|
|
||||||
|
# read it back into a module
|
||||||
|
with open(testasm_bc, "rb") as fin:
|
||||||
|
m2 = Module.from_bitcode(fin)
|
||||||
|
# The default `m.id` is '<string>'.
|
||||||
|
m2.id = m.id # Copy the name from `m`
|
||||||
|
|
||||||
|
self.assertEqual(str(m2).strip(), asm.strip())
|
||||||
|
|
||||||
|
tests.append(TestAsm)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
85
llvm/tests/test_atomic.py
Normal file
85
llvm/tests/test_atomic.py
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestAtomic(TestCase):
|
||||||
|
orderings = ['unordered', 'monotonic', 'acquire',
|
||||||
|
'release', 'acq_rel', 'seq_cst']
|
||||||
|
|
||||||
|
atomic_op = ['xchg', 'add', 'sub', 'and', 'nand', 'or', 'xor',
|
||||||
|
'max', 'min', 'umax', 'umin']
|
||||||
|
|
||||||
|
def test_atomic_cmpxchg(self):
|
||||||
|
mod = Module.new('mod')
|
||||||
|
functype = Type.function(Type.void(), [])
|
||||||
|
func = mod.add_function(functype, name='foo')
|
||||||
|
bb = func.append_basic_block('entry')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
ptr = bldr.alloca(Type.int())
|
||||||
|
|
||||||
|
old = bldr.load(ptr)
|
||||||
|
new = Constant.int(Type.int(), 1234)
|
||||||
|
|
||||||
|
for ordering in self.orderings:
|
||||||
|
inst = bldr.atomic_cmpxchg(ptr, old, new, ordering)
|
||||||
|
self.assertEqual(ordering, str(inst).strip().split(' ')[-1])
|
||||||
|
|
||||||
|
inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False)
|
||||||
|
self.assertEqual('singlethread', str(inst).strip().split(' ')[-2])
|
||||||
|
|
||||||
|
def test_atomic_rmw(self):
|
||||||
|
mod = Module.new('mod')
|
||||||
|
functype = Type.function(Type.void(), [])
|
||||||
|
func = mod.add_function(functype, name='foo')
|
||||||
|
bb = func.append_basic_block('entry')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
ptr = bldr.alloca(Type.int())
|
||||||
|
|
||||||
|
val = Constant.int(Type.int(), 1234)
|
||||||
|
|
||||||
|
for ordering in self.orderings:
|
||||||
|
inst = bldr.atomic_rmw('xchg', ptr, val, ordering)
|
||||||
|
self.assertEqual(ordering, str(inst).split(' ')[-1])
|
||||||
|
|
||||||
|
for op in self.atomic_op:
|
||||||
|
inst = bldr.atomic_rmw(op, ptr, val, ordering)
|
||||||
|
self.assertEqual(op, str(inst).strip().split(' ')[3])
|
||||||
|
|
||||||
|
inst = bldr.atomic_rmw('xchg', ptr, val, ordering, crossthread=False)
|
||||||
|
self.assertEqual('singlethread', str(inst).strip().split(' ')[-2])
|
||||||
|
|
||||||
|
for op in self.atomic_op:
|
||||||
|
atomic_op = getattr(bldr, 'atomic_%s' % op)
|
||||||
|
inst = atomic_op(ptr, val, ordering)
|
||||||
|
self.assertEqual(op, str(inst).strip().split(' ')[3])
|
||||||
|
|
||||||
|
def test_atomic_ldst(self):
|
||||||
|
mod = Module.new('mod')
|
||||||
|
functype = Type.function(Type.void(), [])
|
||||||
|
func = mod.add_function(functype, name='foo')
|
||||||
|
bb = func.append_basic_block('entry')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
ptr = bldr.alloca(Type.int())
|
||||||
|
|
||||||
|
for ordering in self.orderings:
|
||||||
|
loaded = bldr.atomic_load(ptr, ordering)
|
||||||
|
self.assert_('load atomic' in str(loaded))
|
||||||
|
self.assertEqual(ordering,
|
||||||
|
str(loaded).strip().split(' ')[-3].rstrip(','))
|
||||||
|
self.assert_('align 1' in str(loaded))
|
||||||
|
|
||||||
|
stored = bldr.atomic_store(loaded, ptr, ordering)
|
||||||
|
self.assert_('store atomic' in str(stored))
|
||||||
|
self.assertEqual(ordering,
|
||||||
|
str(stored).strip().split(' ')[-3].rstrip(','))
|
||||||
|
self.assert_('align 1' in str(stored))
|
||||||
|
|
||||||
|
fenced = bldr.fence(ordering)
|
||||||
|
self.assertEqual(['fence', ordering],
|
||||||
|
str(fenced).strip().split(' '))
|
||||||
|
|
||||||
|
tests.append(TestAtomic)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
33
llvm/tests/test_attr.py
Normal file
33
llvm/tests/test_attr.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
from llvm.core import Module
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestAttr(TestCase):
|
||||||
|
def make_module(self):
|
||||||
|
test_module = """
|
||||||
|
define void @sum(i32*, i32*) {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
buf = StringIO(test_module)
|
||||||
|
return Module.from_assembly(buf)
|
||||||
|
|
||||||
|
def test_align(self):
|
||||||
|
m = self.make_module()
|
||||||
|
f = m.get_function_named('sum')
|
||||||
|
f.args[0].alignment = 16
|
||||||
|
self.assert_("align 16" in str(f))
|
||||||
|
self.assertEqual(f.args[0].alignment, 16)
|
||||||
|
|
||||||
|
tests.append(TestAttr)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
26
llvm/tests/test_cmp.py
Normal file
26
llvm/tests/test_cmp.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant)
|
||||||
|
import llvm.core as lc
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestCmp(TestCase):
|
||||||
|
def test_arg_attr(self):
|
||||||
|
m = Module.new('oifjda')
|
||||||
|
fnty = Type.function(Type.void(), [Type.int()])
|
||||||
|
func = m.add_function(fnty, 'foo')
|
||||||
|
bb = func.append_basic_block('')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
|
||||||
|
cmpinst = bldr.icmp(lc.ICMP_ULE, func.args[0],
|
||||||
|
Constant.int(Type.int(), 123))
|
||||||
|
self.assertTrue(repr(cmpinst.predicate).startswith('ICMP_ULE'))
|
||||||
|
self.assertEqual(cmpinst.predicate, lc.ICMP_ULE)
|
||||||
|
bldr.ret_void()
|
||||||
|
|
||||||
|
func.verify()
|
||||||
|
|
||||||
|
tests.append(TestCmp)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
23
llvm/tests/test_const_expr.py
Normal file
23
llvm/tests/test_const_expr.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant)
|
||||||
|
import llvm.core as lc
|
||||||
|
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestConstExpr(TestCase):
|
||||||
|
|
||||||
|
def test_constexpr_opcode(self):
|
||||||
|
mod = Module.new('test_constexpr_opcode')
|
||||||
|
func = mod.add_function(Type.function(Type.void(), []), name="foo")
|
||||||
|
builder = Builder.new(func.append_basic_block('entry'))
|
||||||
|
a = builder.inttoptr(Constant.int(Type.int(), 123),
|
||||||
|
Type.pointer(Type.int()))
|
||||||
|
self.assertTrue(isinstance(a, lc.ConstantExpr))
|
||||||
|
self.assertEqual(a.opcode, lc.OPCODE_INTTOPTR)
|
||||||
|
self.assertEqual(a.opcode_name, "inttoptr")
|
||||||
|
|
||||||
|
tests.append(TestConstExpr)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
89
llvm/tests/test_cpu_support.py
Normal file
89
llvm/tests/test_cpu_support.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import unittest
|
||||||
|
import math
|
||||||
|
from llvm.core import (Module, Type, Function, Builder,
|
||||||
|
Constant)
|
||||||
|
from llvm.ee import EngineBuilder
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
from llvm.workaround.avx_support import detect_avx_support
|
||||||
|
from .support import TestCase, tests, skip_if_not_intel_cpu, skip_if
|
||||||
|
|
||||||
|
@skip_if_not_intel_cpu
|
||||||
|
class TestCPUSupport(TestCase):
|
||||||
|
|
||||||
|
def _build_test_module(self):
|
||||||
|
mod = Module.new('test')
|
||||||
|
|
||||||
|
float = Type.double()
|
||||||
|
mysinty = Type.function( float, [float] )
|
||||||
|
mysin = mod.add_function(mysinty, "mysin")
|
||||||
|
block = mysin.append_basic_block("entry")
|
||||||
|
b = Builder.new(block)
|
||||||
|
|
||||||
|
sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float])
|
||||||
|
pow = Function.intrinsic(mod, lc.INTR_POWI, [float])
|
||||||
|
cos = Function.intrinsic(mod, lc.INTR_COS, [float])
|
||||||
|
|
||||||
|
mysin.args[0].name = "x"
|
||||||
|
x = mysin.args[0]
|
||||||
|
one = Constant.real(float, "1")
|
||||||
|
cosx = b.call(cos, [x], "cosx")
|
||||||
|
cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2")
|
||||||
|
onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub
|
||||||
|
sin = b.call(sqrt, [onemc2], "sin")
|
||||||
|
b.ret(sin)
|
||||||
|
return mod, mysin
|
||||||
|
|
||||||
|
def _template(self, mattrs):
|
||||||
|
mod, func = self._build_test_module()
|
||||||
|
ee = self._build_engine(mod, mattrs=mattrs)
|
||||||
|
arg = le.GenericValue.real(Type.double(), 1.234)
|
||||||
|
retval = ee.run_function(func, [arg])
|
||||||
|
|
||||||
|
golden = math.sin(1.234)
|
||||||
|
answer = retval.as_real(Type.double())
|
||||||
|
self.assertTrue(abs(answer-golden)/golden < 1e-5)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_engine(self, mod, mattrs):
|
||||||
|
if mattrs:
|
||||||
|
return EngineBuilder.new(mod).mattrs(mattrs).create()
|
||||||
|
else:
|
||||||
|
return EngineBuilder.new(mod).create()
|
||||||
|
|
||||||
|
def test_cpu_support2(self):
|
||||||
|
features = 'sse3', 'sse41', 'sse42', 'avx'
|
||||||
|
mattrs = ','.join(map(lambda s: '-%s' % s, features))
|
||||||
|
print('disable mattrs', mattrs)
|
||||||
|
self._template(mattrs)
|
||||||
|
|
||||||
|
def test_cpu_support3(self):
|
||||||
|
features = 'sse41', 'sse42', 'avx'
|
||||||
|
mattrs = ','.join(map(lambda s: '-%s' % s, features))
|
||||||
|
print('disable mattrs', mattrs)
|
||||||
|
self._template(mattrs)
|
||||||
|
|
||||||
|
def test_cpu_support4(self):
|
||||||
|
features = 'sse42', 'avx'
|
||||||
|
mattrs = ','.join(map(lambda s: '-%s' % s, features))
|
||||||
|
print('disable mattrs', mattrs)
|
||||||
|
self._template(mattrs)
|
||||||
|
|
||||||
|
def test_cpu_support5(self):
|
||||||
|
features = 'avx',
|
||||||
|
mattrs = ','.join(map(lambda s: '-%s' % s, features))
|
||||||
|
print('disable mattrs', mattrs)
|
||||||
|
self._template(mattrs)
|
||||||
|
|
||||||
|
@skip_if(not detect_avx_support(), msg="no AVX support")
|
||||||
|
def test_cpu_support6(self):
|
||||||
|
features = []
|
||||||
|
mattrs = ','.join(map(lambda s: '-%s' % s, features))
|
||||||
|
print('disable mattrs', mattrs)
|
||||||
|
self._template(mattrs)
|
||||||
|
|
||||||
|
tests.append(TestCPUSupport)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
65
llvm/tests/test_engine_builder.py
Normal file
65
llvm/tests/test_engine_builder.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type, Builder, Constant
|
||||||
|
from llvm.ee import EngineBuilder
|
||||||
|
import llvm.ee as le
|
||||||
|
import llvmpy
|
||||||
|
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestEngineBuilder(TestCase):
|
||||||
|
|
||||||
|
def make_test_module(self):
|
||||||
|
module = Module.new("testmodule")
|
||||||
|
fnty = Type.function(Type.int(), [])
|
||||||
|
function = module.add_function(fnty, 'foo')
|
||||||
|
bb_entry = function.append_basic_block('entry')
|
||||||
|
builder = Builder.new(bb_entry)
|
||||||
|
builder.ret(Constant.int(Type.int(), 0xcafe))
|
||||||
|
module.verify()
|
||||||
|
return module
|
||||||
|
|
||||||
|
def run_foo(self, ee, module):
|
||||||
|
function = module.get_function_named('foo')
|
||||||
|
retval = ee.run_function(function, [])
|
||||||
|
self.assertEqual(retval.as_int(), 0xcafe)
|
||||||
|
|
||||||
|
|
||||||
|
def test_enginebuilder_basic(self):
|
||||||
|
module = self.make_test_module()
|
||||||
|
self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr))
|
||||||
|
ee = EngineBuilder.new(module).create()
|
||||||
|
self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr))
|
||||||
|
self.run_foo(ee, module)
|
||||||
|
|
||||||
|
|
||||||
|
def test_enginebuilder_with_tm(self):
|
||||||
|
tm = le.TargetMachine.new()
|
||||||
|
module = self.make_test_module()
|
||||||
|
self.assertTrue(llvmpy.capsule.has_ownership(module._ptr._ptr))
|
||||||
|
ee = EngineBuilder.new(module).create(tm)
|
||||||
|
self.assertFalse(llvmpy.capsule.has_ownership(module._ptr._ptr))
|
||||||
|
self.run_foo(ee, module)
|
||||||
|
|
||||||
|
def test_enginebuilder_force_jit(self):
|
||||||
|
module = self.make_test_module()
|
||||||
|
ee = EngineBuilder.new(module).force_jit().create()
|
||||||
|
|
||||||
|
self.run_foo(ee, module)
|
||||||
|
#
|
||||||
|
# def test_enginebuilder_force_interpreter(self):
|
||||||
|
# module = self.make_test_module()
|
||||||
|
# ee = EngineBuilder.new(module).force_interpreter().create()
|
||||||
|
#
|
||||||
|
# self.run_foo(ee, module)
|
||||||
|
|
||||||
|
def test_enginebuilder_opt(self):
|
||||||
|
module = self.make_test_module()
|
||||||
|
ee = EngineBuilder.new(module).opt(3).create()
|
||||||
|
|
||||||
|
self.run_foo(ee, module)
|
||||||
|
|
||||||
|
tests.append(TestEngineBuilder)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
37
llvm/tests/test_exact.py
Normal file
37
llvm/tests/test_exact.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestExact(TestCase):
|
||||||
|
def make_module(self):
|
||||||
|
mod = Module.new('asdfa')
|
||||||
|
fnty = Type.function(Type.void(), [Type.int()] * 2)
|
||||||
|
func = mod.add_function(fnty, 'foo')
|
||||||
|
bldr = Builder.new(func.append_basic_block(''))
|
||||||
|
return mod, func, bldr
|
||||||
|
|
||||||
|
def has_exact(self, inst, op):
|
||||||
|
self.assertTrue(('%s exact' % op) in str(inst), "exact flag does not work")
|
||||||
|
|
||||||
|
def _test_template(self, opf, opname):
|
||||||
|
mod, func, bldr = self.make_module()
|
||||||
|
a, b = func.args
|
||||||
|
self.has_exact(opf(bldr, a, b, exact=True), opname)
|
||||||
|
|
||||||
|
def test_udiv_exact(self):
|
||||||
|
self._test_template(Builder.udiv, 'udiv')
|
||||||
|
|
||||||
|
def test_sdiv_exact(self):
|
||||||
|
self._test_template(Builder.sdiv, 'sdiv')
|
||||||
|
|
||||||
|
def test_lshr_exact(self):
|
||||||
|
self._test_template(Builder.lshr, 'lshr')
|
||||||
|
|
||||||
|
def test_ashr_exact(self):
|
||||||
|
self._test_template(Builder.ashr, 'ashr')
|
||||||
|
|
||||||
|
tests.append(TestExact)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
47
llvm/tests/test_execution_engine.py
Normal file
47
llvm/tests/test_execution_engine.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Type
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestExecutionEngine(TestCase):
|
||||||
|
def test_get_pointer_to_global(self):
|
||||||
|
module = lc.Module.new(str(self))
|
||||||
|
gvar = module.add_global_variable(Type.int(), 'hello')
|
||||||
|
X = 1234
|
||||||
|
gvar.initializer = lc.Constant.int(Type.int(), X)
|
||||||
|
|
||||||
|
ee = le.ExecutionEngine.new(module)
|
||||||
|
ptr = ee.get_pointer_to_global(gvar)
|
||||||
|
from ctypes import c_void_p, cast, c_int, POINTER
|
||||||
|
casted = cast(c_void_p(ptr), POINTER(c_int))
|
||||||
|
self.assertEqual(X, casted[0])
|
||||||
|
|
||||||
|
def test_add_global_mapping(self):
|
||||||
|
module = lc.Module.new(str(self))
|
||||||
|
gvar = module.add_global_variable(Type.int(), 'hello')
|
||||||
|
|
||||||
|
fnty = lc.Type.function(Type.int(), [])
|
||||||
|
foo = module.add_function(fnty, name='foo')
|
||||||
|
bldr = lc.Builder.new(foo.append_basic_block('entry'))
|
||||||
|
bldr.ret(bldr.load(gvar))
|
||||||
|
|
||||||
|
ee = le.ExecutionEngine.new(module)
|
||||||
|
from ctypes import c_int, addressof, CFUNCTYPE
|
||||||
|
value = 0xABCD
|
||||||
|
value_ctype = c_int(value)
|
||||||
|
value_pointer = addressof(value_ctype)
|
||||||
|
|
||||||
|
ee.add_global_mapping(gvar, value_pointer)
|
||||||
|
|
||||||
|
foo_addr = ee.get_pointer_to_function(foo)
|
||||||
|
prototype = CFUNCTYPE(c_int)
|
||||||
|
foo_callable = prototype(foo_addr)
|
||||||
|
self.assertEqual(foo_callable(), value)
|
||||||
|
|
||||||
|
tests.append(TestExecutionEngine)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
34
llvm/tests/test_inlining.py
Normal file
34
llvm/tests/test_inlining.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant, inline_function)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestInlining(TestCase):
|
||||||
|
def test_inline_call(self):
|
||||||
|
mod = Module.new(__name__)
|
||||||
|
callee = mod.add_function(Type.function(Type.int(), [Type.int()]),
|
||||||
|
name='bar')
|
||||||
|
|
||||||
|
builder = Builder.new(callee.append_basic_block('entry'))
|
||||||
|
builder.ret(builder.add(callee.args[0], callee.args[0]))
|
||||||
|
|
||||||
|
caller = mod.add_function(Type.function(Type.int(), []),
|
||||||
|
name='foo')
|
||||||
|
|
||||||
|
builder = Builder.new(caller.append_basic_block('entry'))
|
||||||
|
callinst = builder.call(callee, [Constant.int(Type.int(), 1234)])
|
||||||
|
builder.ret(callinst)
|
||||||
|
|
||||||
|
pre_inlining = str(caller)
|
||||||
|
self.assertIn('call', pre_inlining)
|
||||||
|
|
||||||
|
self.assertTrue(inline_function(callinst))
|
||||||
|
|
||||||
|
post_inlining = str(caller)
|
||||||
|
self.assertNotIn('call', post_inlining)
|
||||||
|
self.assertIn('2468', post_inlining)
|
||||||
|
|
||||||
|
tests.append(TestInlining)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
31
llvm/tests/test_intel_native_asm.py
Normal file
31
llvm/tests/test_intel_native_asm.py
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Builder, Module, Type
|
||||||
|
import llvm.core as lc
|
||||||
|
from .support import TestCase, skip_if_not_intel_cpu, isolated_tests
|
||||||
|
|
||||||
|
@skip_if_not_intel_cpu
|
||||||
|
class TestNativeAsm(TestCase):
|
||||||
|
|
||||||
|
def test_asm(self):
|
||||||
|
m = Module.new('module1')
|
||||||
|
|
||||||
|
foo = m.add_function(Type.function(Type.int(),
|
||||||
|
[Type.int(), Type.int()]),
|
||||||
|
name="foo")
|
||||||
|
bldr = Builder.new(foo.append_basic_block('entry'))
|
||||||
|
x = bldr.add(foo.args[0], foo.args[1])
|
||||||
|
bldr.ret(x)
|
||||||
|
|
||||||
|
att_syntax = m.to_native_assembly()
|
||||||
|
os.environ["LLVMPY_OPTIONS"] = "-x86-asm-syntax=intel"
|
||||||
|
lc.parse_environment_options(sys.argv[0], "LLVMPY_OPTIONS")
|
||||||
|
intel_syntax = m.to_native_assembly()
|
||||||
|
|
||||||
|
self.assertNotEqual(att_syntax, intel_syntax)
|
||||||
|
|
||||||
|
isolated_tests.append(__name__)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
113
llvm/tests/test_intrinsic.py
Normal file
113
llvm/tests/test_intrinsic.py
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
from llvm.core import (Module, Type, Function, Builder, Constant)
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
from .support import TestCase, tests, BITS
|
||||||
|
|
||||||
|
class TestIntrinsic(TestCase):
|
||||||
|
def test_bswap(self):
|
||||||
|
# setup a function and a builder
|
||||||
|
mod = Module.new('test')
|
||||||
|
functy = Type.function(Type.int(), [])
|
||||||
|
func = mod.add_function(functy, "showme")
|
||||||
|
block = func.append_basic_block("entry")
|
||||||
|
b = Builder.new(block)
|
||||||
|
|
||||||
|
# let's do bswap on a 32-bit integer using llvm.bswap
|
||||||
|
val = Constant.int(Type.int(), 0x42)
|
||||||
|
bswap = Function.intrinsic(mod, lc.INTR_BSWAP, [Type.int()])
|
||||||
|
|
||||||
|
bswap_res = b.call(bswap, [val])
|
||||||
|
b.ret(bswap_res)
|
||||||
|
|
||||||
|
# logging.debug(mod)
|
||||||
|
|
||||||
|
# the output is:
|
||||||
|
#
|
||||||
|
# ; ModuleID = 'test'
|
||||||
|
#
|
||||||
|
# define void @showme() {
|
||||||
|
# entry:
|
||||||
|
# %0 = call i32 @llvm.bswap.i32(i32 42)
|
||||||
|
# ret i32 %0
|
||||||
|
# }
|
||||||
|
|
||||||
|
# let's run the function
|
||||||
|
ee = le.ExecutionEngine.new(mod)
|
||||||
|
retval = ee.run_function(func, [])
|
||||||
|
self.assertEqual(retval.as_int(), 0x42000000)
|
||||||
|
|
||||||
|
def test_mysin(self):
|
||||||
|
if sys.platform == 'win32' and BITS == 32:
|
||||||
|
# float32 support is known to fail on 32-bit Windows
|
||||||
|
return
|
||||||
|
|
||||||
|
# mysin(x) = sqrt(1.0 - pow(cos(x), 2))
|
||||||
|
mod = Module.new('test')
|
||||||
|
|
||||||
|
float = Type.float()
|
||||||
|
mysinty = Type.function( float, [float] )
|
||||||
|
mysin = mod.add_function(mysinty, "mysin")
|
||||||
|
block = mysin.append_basic_block("entry")
|
||||||
|
b = Builder.new(block)
|
||||||
|
|
||||||
|
sqrt = Function.intrinsic(mod, lc.INTR_SQRT, [float])
|
||||||
|
pow = Function.intrinsic(mod, lc.INTR_POWI, [float])
|
||||||
|
cos = Function.intrinsic(mod, lc.INTR_COS, [float])
|
||||||
|
|
||||||
|
mysin.args[0].name = "x"
|
||||||
|
x = mysin.args[0]
|
||||||
|
one = Constant.real(float, "1")
|
||||||
|
cosx = b.call(cos, [x], "cosx")
|
||||||
|
cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2")
|
||||||
|
onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub
|
||||||
|
sin = b.call(sqrt, [onemc2], "sin")
|
||||||
|
b.ret(sin)
|
||||||
|
#logging.debug(mod)
|
||||||
|
|
||||||
|
# ; ModuleID = 'test'
|
||||||
|
#
|
||||||
|
# define void @showme() {
|
||||||
|
# entry:
|
||||||
|
# call i32 @llvm.bswap.i32( i32 42 ) ; <i32>:0 [#uses
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# declare i32 @llvm.bswap.i32(i32) nounwind readnone
|
||||||
|
#
|
||||||
|
# define float @mysin(float %x) {
|
||||||
|
# entry:
|
||||||
|
# %cosx = call float @llvm.cos.f32( float %x ) ; <float
|
||||||
|
# %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 )
|
||||||
|
# %onemc2 = sub float 1.000000e+00, %cos2 ; <float> [#uses
|
||||||
|
# %sin = call float @llvm.sqrt.f32( float %onemc2 )
|
||||||
|
# ret float %sin
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# declare float @llvm.sqrt.f32(float) nounwind readnone
|
||||||
|
#
|
||||||
|
# declare float @llvm.powi.f32(float, i32) nounwind readnone
|
||||||
|
#
|
||||||
|
# declare float @llvm.cos.f32(float) nounwind readnone
|
||||||
|
|
||||||
|
# let's run the function
|
||||||
|
|
||||||
|
from llvm.workaround.avx_support import detect_avx_support
|
||||||
|
if not detect_avx_support():
|
||||||
|
ee = le.EngineBuilder.new(mod).mattrs("-avx").create()
|
||||||
|
else:
|
||||||
|
ee = le.EngineBuilder.new(mod).create()
|
||||||
|
|
||||||
|
arg = le.GenericValue.real(Type.float(), 1.234)
|
||||||
|
retval = ee.run_function(mysin, [arg])
|
||||||
|
|
||||||
|
golden = math.sin(1.234)
|
||||||
|
answer = retval.as_real(Type.float())
|
||||||
|
self.assertTrue(abs(answer-golden)/golden < 1e-5)
|
||||||
|
|
||||||
|
tests.append(TestIntrinsic)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
99
llvm/tests/test_intrinsic_basic.py
Normal file
99
llvm/tests/test_intrinsic_basic.py
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import math
|
||||||
|
from llvm.core import (Module, Type, Function, Builder)
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
from .support import TestCase, BITS, tests
|
||||||
|
|
||||||
|
class TestIntrinsicBasic(TestCase):
|
||||||
|
|
||||||
|
def _build_module(self, float):
|
||||||
|
mod = Module.new('test')
|
||||||
|
functy = Type.function(float, [float])
|
||||||
|
func = mod.add_function(functy, "mytest%s" % float)
|
||||||
|
block = func.append_basic_block("entry")
|
||||||
|
b = Builder.new(block)
|
||||||
|
return mod, func, b
|
||||||
|
|
||||||
|
def _template(self, mod, func, pyfunc):
|
||||||
|
float = func.type.pointee.return_type
|
||||||
|
|
||||||
|
from llvm.workaround.avx_support import detect_avx_support
|
||||||
|
if not detect_avx_support():
|
||||||
|
ee = le.EngineBuilder.new(mod).mattrs("-avx").create()
|
||||||
|
else:
|
||||||
|
ee = le.EngineBuilder.new(mod).create()
|
||||||
|
arg = le.GenericValue.real(float, 1.234)
|
||||||
|
retval = ee.run_function(func, [arg])
|
||||||
|
golden = pyfunc(1.234)
|
||||||
|
answer = retval.as_real(float)
|
||||||
|
self.assertTrue(abs(answer - golden) / golden < 1e-7)
|
||||||
|
|
||||||
|
def test_sqrt_f32(self):
|
||||||
|
float = Type.float()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_SQRT, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.sqrt)
|
||||||
|
|
||||||
|
def test_sqrt_f64(self):
|
||||||
|
float = Type.double()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_SQRT, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.sqrt)
|
||||||
|
|
||||||
|
def test_cos_f32(self):
|
||||||
|
if sys.platform == 'win32' and BITS == 32:
|
||||||
|
# float32 support is known to fail on 32-bit Windows
|
||||||
|
return
|
||||||
|
float = Type.float()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_COS, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.cos)
|
||||||
|
|
||||||
|
def test_cos_f64(self):
|
||||||
|
float = Type.double()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_COS, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.cos)
|
||||||
|
|
||||||
|
def test_sin_f32(self):
|
||||||
|
if sys.platform == 'win32' and BITS == 32:
|
||||||
|
# float32 support is known to fail on 32-bit Windows
|
||||||
|
return
|
||||||
|
float = Type.float()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_SIN, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.sin)
|
||||||
|
|
||||||
|
def test_sin_f64(self):
|
||||||
|
float = Type.double()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_SIN, [float])
|
||||||
|
b.ret(b.call(intr, func.args))
|
||||||
|
self._template(mod, func, math.sin)
|
||||||
|
|
||||||
|
def test_powi_f32(self):
|
||||||
|
float = Type.float()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_POWI, [float])
|
||||||
|
b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)]))
|
||||||
|
self._template(mod, func, lambda x: x**2)
|
||||||
|
|
||||||
|
def test_powi_f64(self):
|
||||||
|
float = Type.double()
|
||||||
|
mod, func, b = self._build_module(float)
|
||||||
|
intr = Function.intrinsic(mod, lc.INTR_POWI, [float])
|
||||||
|
b.ret(b.call(intr, [func.args[0], lc.Constant.int(Type.int(), 2)]))
|
||||||
|
self._template(mod, func, lambda x: x**2)
|
||||||
|
|
||||||
|
tests.append(TestIntrinsicBasic)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
26
llvm/tests/test_issue_10.py
Normal file
26
llvm/tests/test_issue_10.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestIssue10(TestCase):
|
||||||
|
def test_issue10(self):
|
||||||
|
m = Module.new('a')
|
||||||
|
ti = Type.int()
|
||||||
|
tf = Type.function(ti, [ti, ti])
|
||||||
|
|
||||||
|
f = m.add_function(tf, "func1")
|
||||||
|
|
||||||
|
bb = f.append_basic_block('entry')
|
||||||
|
|
||||||
|
b = Builder.new(bb)
|
||||||
|
|
||||||
|
# There are no instructions in bb. Positioning of the
|
||||||
|
# builder at beginning (or end) should succeed (trivially).
|
||||||
|
b.position_at_end(bb)
|
||||||
|
b.position_at_beginning(bb)
|
||||||
|
|
||||||
|
tests.append(TestIssue10)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
34
llvm/tests/test_llrt.py
Normal file
34
llvm/tests/test_llrt.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import unittest
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestLLRT(TestCase):
|
||||||
|
def test_llrt_divmod(self):
|
||||||
|
from llvm import llrt
|
||||||
|
m = lc.Module.new('testllrt')
|
||||||
|
longlong = lc.Type.int(64)
|
||||||
|
lfunc = m.add_function(lc.Type.function(longlong, [longlong, longlong]), 'foo')
|
||||||
|
bldr = lc.Builder.new(lfunc.append_basic_block(''))
|
||||||
|
bldr.ret(bldr.udiv(*lfunc.args))
|
||||||
|
|
||||||
|
llrt.replace_divmod64(lfunc)
|
||||||
|
|
||||||
|
rt = llrt.LLRT()
|
||||||
|
rt.install_symbols()
|
||||||
|
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
pointer = engine.get_pointer_to_function(lfunc)
|
||||||
|
|
||||||
|
from ctypes import CFUNCTYPE, c_uint64
|
||||||
|
func = CFUNCTYPE(c_uint64, c_uint64, c_uint64)(pointer)
|
||||||
|
a, b = 98342, 2231
|
||||||
|
self.assertEqual(func(98342, 2231), 98342 // 2231)
|
||||||
|
|
||||||
|
rt.uninstall_symbols()
|
||||||
|
|
||||||
|
tests.append(TestLLRT)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
73
llvm/tests/test_mcjit.py
Normal file
73
llvm/tests/test_mcjit.py
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import llvm
|
||||||
|
from llvm.core import (Module, Type, Builder)
|
||||||
|
from llvm.ee import EngineBuilder
|
||||||
|
|
||||||
|
import llvm.ee as le
|
||||||
|
from .support import TestCase, tests, BITS
|
||||||
|
|
||||||
|
class TestMCJIT(TestCase):
|
||||||
|
def test_mcjit(self):
|
||||||
|
m = Module.new('oidfjs')
|
||||||
|
fnty = Type.function(Type.int(), [Type.int(), Type.int()])
|
||||||
|
func = m.add_function(fnty, 'foo')
|
||||||
|
bb = func.append_basic_block('')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
bldr.ret(bldr.add(*func.args))
|
||||||
|
|
||||||
|
func.verify()
|
||||||
|
|
||||||
|
engine = EngineBuilder.new(m).mcjit(True).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
from ctypes import c_int, CFUNCTYPE
|
||||||
|
callee = CFUNCTYPE(c_int, c_int, c_int)(ptr)
|
||||||
|
self.assertEqual(321 + 123, callee(321, 123))
|
||||||
|
|
||||||
|
def test_multi_module_linking(self):
|
||||||
|
# generate external library module
|
||||||
|
m = Module.new('external-library-module')
|
||||||
|
fnty = Type.function(Type.int(), [Type.int(), Type.int()])
|
||||||
|
libfname = 'myadd'
|
||||||
|
func = m.add_function(fnty, libfname)
|
||||||
|
bb = func.append_basic_block('')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
bldr.ret(bldr.add(*func.args))
|
||||||
|
func.verify()
|
||||||
|
|
||||||
|
# JIT the lib module and bind dynamic symbol
|
||||||
|
libengine = EngineBuilder.new(m).mcjit(True).create()
|
||||||
|
myadd_ptr = libengine.get_pointer_to_function(func)
|
||||||
|
le.dylib_add_symbol(libfname, myadd_ptr)
|
||||||
|
|
||||||
|
# reference external library
|
||||||
|
m = Module.new('user')
|
||||||
|
fnty = Type.function(Type.int(), [Type.int(), Type.int()])
|
||||||
|
func = m.add_function(fnty, 'foo')
|
||||||
|
bb = func.append_basic_block('')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
extadd = m.get_or_insert_function(fnty, name=libfname)
|
||||||
|
bldr.ret(bldr.call(extadd, func.args))
|
||||||
|
func.verify()
|
||||||
|
|
||||||
|
# JIT the user module
|
||||||
|
engine = EngineBuilder.new(m).mcjit(True).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
self.assertEqual(myadd_ptr,
|
||||||
|
engine.get_pointer_to_named_function(libfname))
|
||||||
|
|
||||||
|
from ctypes import c_int, CFUNCTYPE
|
||||||
|
callee = CFUNCTYPE(c_int, c_int, c_int)(ptr)
|
||||||
|
self.assertEqual(321 + 123, callee(321, 123))
|
||||||
|
|
||||||
|
|
||||||
|
if (llvm.version >= (3, 3) and
|
||||||
|
not (sys.platform.startswith('win32') and BITS == 64)):
|
||||||
|
# MCJIT broken in 3.2, the test will segfault in OSX?
|
||||||
|
# Compatbility problem on windows 7 64-bit?
|
||||||
|
tests.append(TestMCJIT)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
25
llvm/tests/test_metadata.py
Normal file
25
llvm/tests/test_metadata.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Constant, MetaData, MetaDataString)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestMetaData(TestCase):
|
||||||
|
# test module metadata
|
||||||
|
def test_metadata(self):
|
||||||
|
m = Module.new('a')
|
||||||
|
t = Type.int()
|
||||||
|
metadata = MetaData.get(m, [Constant.int(t, 100),
|
||||||
|
MetaDataString.get(m, 'abcdef'),
|
||||||
|
None])
|
||||||
|
MetaData.add_named_operand(m, 'foo', metadata)
|
||||||
|
self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata])
|
||||||
|
self.assertEqual(MetaData.get_named_operands(m, 'bar'), [])
|
||||||
|
self.assertEqual(len(metadata.operands), 3)
|
||||||
|
self.assertEqual(metadata.operands[0].z_ext_value, 100)
|
||||||
|
self.assertEqual(metadata.operands[1].string, 'abcdef')
|
||||||
|
self.assertTrue(metadata.operands[2] is None)
|
||||||
|
|
||||||
|
tests.append(TestMetaData)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
20
llvm/tests/test_named_metadata.py
Normal file
20
llvm/tests/test_named_metadata.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Constant, MetaData)
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
|
||||||
|
class TestNamedMetaData(TestCase):
|
||||||
|
def test_named_md(self):
|
||||||
|
m = Module.new('test_named_md')
|
||||||
|
nmd = m.get_or_insert_named_metadata('something')
|
||||||
|
md = MetaData.get(m, [Constant.int(Type.int(), 0xbeef)])
|
||||||
|
nmd.add(md)
|
||||||
|
self.assertTrue(str(nmd).startswith('!something'))
|
||||||
|
ir = str(m)
|
||||||
|
self.assertTrue('!something' in ir)
|
||||||
|
|
||||||
|
tests.append(TestNamedMetaData)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
81
llvm/tests/test_native.py
Normal file
81
llvm/tests/test_native.py
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
from distutils.spawn import find_executable
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant)
|
||||||
|
from .support import TestCase, IS_PY3K, tests, skip_if
|
||||||
|
|
||||||
|
@skip_if(sys.platform in ('win32', 'darwin'))
|
||||||
|
class TestNative(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.tmpdir = tempfile.mkdtemp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
shutil.rmtree(self.tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
def _make_module(self):
|
||||||
|
m = Module.new('module1')
|
||||||
|
m.add_global_variable(Type.int(), 'i')
|
||||||
|
|
||||||
|
fty = Type.function(Type.int(), [])
|
||||||
|
f = m.add_function(fty, name='main')
|
||||||
|
|
||||||
|
bldr = Builder.new(f.append_basic_block('entry'))
|
||||||
|
bldr.ret(Constant.int(Type.int(), 0xab))
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
def _compile(self, src):
|
||||||
|
cc = find_executable('cc')
|
||||||
|
if not cc:
|
||||||
|
return
|
||||||
|
|
||||||
|
dst = os.path.join(self.tmpdir, 'llvmobj.out')
|
||||||
|
s = subprocess.call([cc, '-o', dst, src])
|
||||||
|
if s != 0:
|
||||||
|
raise Exception("Cannot compile")
|
||||||
|
|
||||||
|
s = subprocess.call([dst])
|
||||||
|
self.assertEqual(s, 0xab)
|
||||||
|
|
||||||
|
def test_assembly(self):
|
||||||
|
# if sys.platform == 'darwin':
|
||||||
|
# # skip this test on MacOSX for now
|
||||||
|
# return
|
||||||
|
|
||||||
|
m = self._make_module()
|
||||||
|
output = m.to_native_assembly()
|
||||||
|
|
||||||
|
src = os.path.join(self.tmpdir, 'llvmasm.s')
|
||||||
|
with open(src, 'wb') as fout:
|
||||||
|
if IS_PY3K:
|
||||||
|
fout.write(output.encode('utf-8'))
|
||||||
|
else:
|
||||||
|
fout.write(output)
|
||||||
|
|
||||||
|
self._compile(src)
|
||||||
|
|
||||||
|
def test_object(self):
|
||||||
|
'''
|
||||||
|
Note: Older Darwin with GCC will report missing _main symbol when
|
||||||
|
compile the object file to an executable.
|
||||||
|
'''
|
||||||
|
m = self._make_module()
|
||||||
|
output = m.to_native_object()
|
||||||
|
|
||||||
|
src = os.path.join(self.tmpdir, 'llvmobj.o')
|
||||||
|
with open(src, 'wb') as fout:
|
||||||
|
fout.write(output)
|
||||||
|
|
||||||
|
self._compile(src)
|
||||||
|
|
||||||
|
tests.append(TestNative)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
48
llvm/tests/test_nuw_nsw.py
Normal file
48
llvm/tests/test_nuw_nsw.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type, Builder
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestNUWNSW(TestCase):
|
||||||
|
def make_module(self):
|
||||||
|
mod = Module.new('asdfa')
|
||||||
|
fnty = Type.function(Type.void(), [Type.int()] * 2)
|
||||||
|
func = mod.add_function(fnty, 'foo')
|
||||||
|
bldr = Builder.new(func.append_basic_block(''))
|
||||||
|
return mod, func, bldr
|
||||||
|
|
||||||
|
def has_nsw(self, inst, op):
|
||||||
|
self.assertTrue(('%s nsw' % op) in str(inst), "NSW flag does not work")
|
||||||
|
|
||||||
|
def has_nuw(self, inst, op):
|
||||||
|
self.assertTrue(('%s nuw' % op) in str(inst), "NUW flag does not work")
|
||||||
|
|
||||||
|
def _test_template(self, opf, opname):
|
||||||
|
mod, func, bldr = self.make_module()
|
||||||
|
a, b = func.args
|
||||||
|
self.has_nsw(opf(bldr, a, b, nsw=True), opname)
|
||||||
|
self.has_nuw(opf(bldr, a, b, nuw=True), opname)
|
||||||
|
|
||||||
|
def test_add_nuw_nsw(self):
|
||||||
|
self._test_template(Builder.add, 'add')
|
||||||
|
|
||||||
|
def test_sub_nuw_nsw(self):
|
||||||
|
self._test_template(Builder.sub, 'sub')
|
||||||
|
|
||||||
|
def test_mul_nuw_nsw(self):
|
||||||
|
self._test_template(Builder.mul, 'mul')
|
||||||
|
|
||||||
|
def test_shl_nuw_nsw(self):
|
||||||
|
self._test_template(Builder.shl, 'shl')
|
||||||
|
|
||||||
|
def test_neg_nuw_nsw(self):
|
||||||
|
mod, func, bldr = self.make_module()
|
||||||
|
a, b = func.args
|
||||||
|
self.has_nsw(bldr.neg(a, nsw=True), 'sub')
|
||||||
|
self.has_nuw(bldr.neg(a, nuw=True), 'sub')
|
||||||
|
|
||||||
|
|
||||||
|
tests.append(TestNUWNSW)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
107
llvm/tests/test_obj_cache.py
Normal file
107
llvm/tests/test_obj_cache.py
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type, GlobalVariable, Function, Builder
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestObjCache(TestCase):
|
||||||
|
|
||||||
|
def test_objcache(self):
|
||||||
|
# Testing module aliasing
|
||||||
|
m1 = Module.new('a')
|
||||||
|
t = Type.int()
|
||||||
|
ft = Type.function(t, [t])
|
||||||
|
f1 = m1.add_function(ft, "func")
|
||||||
|
m2 = f1.module
|
||||||
|
self.assert_(m1 is m2)
|
||||||
|
|
||||||
|
# Testing global vairable aliasing 1
|
||||||
|
gv1 = GlobalVariable.new(m1, t, "gv")
|
||||||
|
gv2 = GlobalVariable.get(m1, "gv")
|
||||||
|
self.assert_(gv1 is gv2)
|
||||||
|
|
||||||
|
# Testing global vairable aliasing 2
|
||||||
|
gv3 = m1.global_variables[0]
|
||||||
|
self.assert_(gv1 is gv3)
|
||||||
|
|
||||||
|
# Testing global vairable aliasing 3
|
||||||
|
gv2 = None
|
||||||
|
gv3 = None
|
||||||
|
|
||||||
|
gv1.delete()
|
||||||
|
|
||||||
|
gv4 = GlobalVariable.new(m1, t, "gv")
|
||||||
|
|
||||||
|
self.assert_(gv1 is not gv4)
|
||||||
|
|
||||||
|
# Testing function aliasing 1
|
||||||
|
b1 = f1.append_basic_block('entry')
|
||||||
|
f2 = b1.function
|
||||||
|
self.assert_(f1 is f2)
|
||||||
|
|
||||||
|
# Testing function aliasing 2
|
||||||
|
f3 = m1.get_function_named("func")
|
||||||
|
self.assert_(f1 is f3)
|
||||||
|
|
||||||
|
# Testing function aliasing 3
|
||||||
|
f4 = Function.get_or_insert(m1, ft, "func")
|
||||||
|
self.assert_(f1 is f4)
|
||||||
|
|
||||||
|
# Testing function aliasing 4
|
||||||
|
f5 = Function.get(m1, "func")
|
||||||
|
self.assert_(f1 is f5)
|
||||||
|
|
||||||
|
# Testing function aliasing 5
|
||||||
|
f6 = m1.get_or_insert_function(ft, "func")
|
||||||
|
self.assert_(f1 is f6)
|
||||||
|
|
||||||
|
# Testing function aliasing 6
|
||||||
|
f7 = m1.functions[0]
|
||||||
|
self.assert_(f1 is f7)
|
||||||
|
|
||||||
|
# Testing argument aliasing
|
||||||
|
a1 = f1.args[0]
|
||||||
|
a2 = f1.args[0]
|
||||||
|
self.assert_(a1 is a2)
|
||||||
|
|
||||||
|
# Testing basic block aliasing 1
|
||||||
|
b2 = f1.basic_blocks[0]
|
||||||
|
self.assert_(b1 is b2)
|
||||||
|
|
||||||
|
# Testing basic block aliasing 2
|
||||||
|
b3 = f1.entry_basic_block
|
||||||
|
self.assert_(b1 is b3)
|
||||||
|
|
||||||
|
# Testing basic block aliasing 3
|
||||||
|
b31 = f1.entry_basic_block
|
||||||
|
self.assert_(b1 is b31)
|
||||||
|
|
||||||
|
# Testing basic block aliasing 4
|
||||||
|
bldr = Builder.new(b1)
|
||||||
|
b4 = bldr.basic_block
|
||||||
|
self.assert_(b1 is b4)
|
||||||
|
|
||||||
|
# Testing basic block aliasing 5
|
||||||
|
i1 = bldr.ret_void()
|
||||||
|
b5 = i1.basic_block
|
||||||
|
self.assert_(b1 is b5)
|
||||||
|
|
||||||
|
# Testing instruction aliasing 1
|
||||||
|
i2 = b5.instructions[0]
|
||||||
|
self.assert_(i1 is i2)
|
||||||
|
|
||||||
|
# phi node
|
||||||
|
phi = bldr.phi(t)
|
||||||
|
phi.add_incoming(f1.args[0], b1)
|
||||||
|
v2 = phi.get_incoming_value(0)
|
||||||
|
b6 = phi.get_incoming_block(0)
|
||||||
|
|
||||||
|
# Testing PHI / basic block aliasing 5
|
||||||
|
self.assert_(b1 is b6)
|
||||||
|
|
||||||
|
# Testing PHI / value aliasing
|
||||||
|
self.assert_(f1.args[0] is v2)
|
||||||
|
|
||||||
|
tests.append(TestObjCache)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
38
llvm/tests/test_opaque.py
Normal file
38
llvm/tests/test_opaque.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import unittest
|
||||||
|
import llvm
|
||||||
|
from llvm.core import Type
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestOpaque(TestCase):
|
||||||
|
|
||||||
|
def test_opaque(self):
|
||||||
|
# Create an opaque type
|
||||||
|
ts = Type.opaque('mystruct')
|
||||||
|
self.assertTrue('type opaque' in str(ts))
|
||||||
|
self.assertTrue(ts.is_opaque)
|
||||||
|
self.assertTrue(ts.is_identified)
|
||||||
|
self.assertFalse(ts.is_literal)
|
||||||
|
#print(ts)
|
||||||
|
|
||||||
|
# Create a recursive type
|
||||||
|
ts.set_body([Type.int(), Type.pointer(ts)])
|
||||||
|
|
||||||
|
self.assertEqual(ts.elements[0], Type.int())
|
||||||
|
self.assertEqual(ts.elements[1], Type.pointer(ts))
|
||||||
|
self.assertEqual(ts.elements[1].pointee, ts)
|
||||||
|
self.assertFalse(ts.is_opaque) # is not longer a opaque type
|
||||||
|
#print(ts)
|
||||||
|
|
||||||
|
with self.assertRaises(llvm.LLVMException):
|
||||||
|
# Cannot redefine
|
||||||
|
ts.set_body([])
|
||||||
|
|
||||||
|
def test_opaque_with_no_name(self):
|
||||||
|
with self.assertRaises(llvm.LLVMException):
|
||||||
|
Type.opaque('')
|
||||||
|
|
||||||
|
tests.append(TestOpaque)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
66
llvm/tests/test_operands.py
Normal file
66
llvm/tests/test_operands.py
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
|
||||||
|
from llvm.core import Module
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestOperands(TestCase):
|
||||||
|
# implement a test function
|
||||||
|
test_module = """
|
||||||
|
define i32 @prod(i32, i32) {
|
||||||
|
entry:
|
||||||
|
%2 = mul i32 %0, %1
|
||||||
|
ret i32 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test_func(i32, i32, i32) {
|
||||||
|
entry:
|
||||||
|
%tmp1 = call i32 @prod(i32 %0, i32 %1)
|
||||||
|
%tmp2 = add i32 %tmp1, %2
|
||||||
|
%tmp3 = add i32 %tmp2, 1
|
||||||
|
%tmp4 = add i32 %tmp3, -1
|
||||||
|
%tmp5 = add i64 -81985529216486895, 12297829382473034410
|
||||||
|
ret i32 %tmp4
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
def test_operands(self):
|
||||||
|
m = Module.from_assembly(StringIO(self.test_module))
|
||||||
|
|
||||||
|
test_func = m.get_function_named("test_func")
|
||||||
|
prod = m.get_function_named("prod")
|
||||||
|
|
||||||
|
# test operands
|
||||||
|
i1 = test_func.basic_blocks[0].instructions[0]
|
||||||
|
i2 = test_func.basic_blocks[0].instructions[1]
|
||||||
|
i3 = test_func.basic_blocks[0].instructions[2]
|
||||||
|
i4 = test_func.basic_blocks[0].instructions[3]
|
||||||
|
i5 = test_func.basic_blocks[0].instructions[4]
|
||||||
|
|
||||||
|
self.assertEqual(i1.operand_count, 3)
|
||||||
|
self.assertEqual(i2.operand_count, 2)
|
||||||
|
|
||||||
|
self.assertEqual(i3.operands[1].z_ext_value, 1)
|
||||||
|
self.assertEqual(i3.operands[1].s_ext_value, 1)
|
||||||
|
self.assertEqual(i4.operands[1].z_ext_value, 0xffffffff)
|
||||||
|
self.assertEqual(i4.operands[1].s_ext_value, -1)
|
||||||
|
self.assertEqual(i5.operands[0].s_ext_value, -81985529216486895)
|
||||||
|
self.assertEqual(i5.operands[1].z_ext_value, 12297829382473034410)
|
||||||
|
|
||||||
|
self.assert_(i1.operands[-1] is prod)
|
||||||
|
self.assert_(i1.operands[0] is test_func.args[0])
|
||||||
|
self.assert_(i1.operands[1] is test_func.args[1])
|
||||||
|
self.assert_(i2.operands[0] is i1)
|
||||||
|
self.assert_(i2.operands[1] is test_func.args[2])
|
||||||
|
self.assertEqual(len(i1.operands), 3)
|
||||||
|
self.assertEqual(len(i2.operands), 2)
|
||||||
|
|
||||||
|
self.assert_(i1.called_function is prod)
|
||||||
|
|
||||||
|
tests.append(TestOperands)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
143
llvm/tests/test_passes.py
Normal file
143
llvm/tests/test_passes.py
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from StringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from io import StringIO
|
||||||
|
import llvm
|
||||||
|
from llvm.core import Module
|
||||||
|
import llvm.passes as lp
|
||||||
|
import llvm.ee as le
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
|
||||||
|
class TestPasses(TestCase):
|
||||||
|
# Create a module.
|
||||||
|
asm = """
|
||||||
|
|
||||||
|
define i32 @test() nounwind {
|
||||||
|
ret i32 42
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test1() nounwind {
|
||||||
|
entry:
|
||||||
|
%tmp = alloca i32
|
||||||
|
store i32 42, i32* %tmp, align 4
|
||||||
|
%tmp1 = load i32* %tmp, align 4
|
||||||
|
%tmp2 = call i32 @test()
|
||||||
|
%tmp3 = load i32* %tmp, align 4
|
||||||
|
%tmp4 = load i32* %tmp, align 4
|
||||||
|
ret i32 %tmp1
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test2() nounwind {
|
||||||
|
entry:
|
||||||
|
%tmp = call i32 @test()
|
||||||
|
ret i32 %tmp
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
def test_passes(self):
|
||||||
|
m = Module.from_assembly(StringIO(self.asm))
|
||||||
|
|
||||||
|
fn_test1 = m.get_function_named('test1')
|
||||||
|
fn_test2 = m.get_function_named('test2')
|
||||||
|
|
||||||
|
original_test1 = str(fn_test1)
|
||||||
|
original_test2 = str(fn_test2)
|
||||||
|
|
||||||
|
# Let's run a module-level inlining pass. First, create a pass manager.
|
||||||
|
pm = lp.PassManager.new()
|
||||||
|
|
||||||
|
# Add the target data as the first "pass". This is mandatory.
|
||||||
|
pm.add(le.TargetData.new(''))
|
||||||
|
|
||||||
|
# Add the inlining pass.
|
||||||
|
pm.add(lp.PASS_INLINE)
|
||||||
|
|
||||||
|
# Run it!
|
||||||
|
pm.run(m)
|
||||||
|
|
||||||
|
# Done with the pass manager.
|
||||||
|
del pm
|
||||||
|
|
||||||
|
# Make sure test2 is inlined
|
||||||
|
self.assertNotEqual(str(fn_test2).strip(), original_test2.strip())
|
||||||
|
|
||||||
|
bb_entry = fn_test2.basic_blocks[0]
|
||||||
|
|
||||||
|
self.assertEqual(len(bb_entry.instructions), 1)
|
||||||
|
self.assertEqual(bb_entry.instructions[0].opcode_name, 'ret')
|
||||||
|
|
||||||
|
# Let's run a DCE pass on the the function 'test1' now. First create a
|
||||||
|
# function pass manager.
|
||||||
|
fpm = lp.FunctionPassManager.new(m)
|
||||||
|
|
||||||
|
# Add the target data as first "pass". This is mandatory.
|
||||||
|
fpm.add(le.TargetData.new(''))
|
||||||
|
|
||||||
|
# Add a DCE pass
|
||||||
|
fpm.add(lp.PASS_ADCE)
|
||||||
|
|
||||||
|
# Run the pass on the function 'test1'
|
||||||
|
fpm.run(m.get_function_named('test1'))
|
||||||
|
|
||||||
|
# Make sure test1 is modified
|
||||||
|
self.assertNotEqual(str(fn_test1).strip(), original_test1.strip())
|
||||||
|
|
||||||
|
def test_passes_with_pmb(self):
|
||||||
|
m = Module.from_assembly(StringIO(self.asm))
|
||||||
|
|
||||||
|
fn_test1 = m.get_function_named('test1')
|
||||||
|
fn_test2 = m.get_function_named('test2')
|
||||||
|
|
||||||
|
original_test1 = str(fn_test1)
|
||||||
|
original_test2 = str(fn_test2)
|
||||||
|
|
||||||
|
# Try out the PassManagerBuilder
|
||||||
|
|
||||||
|
pmb = lp.PassManagerBuilder.new()
|
||||||
|
|
||||||
|
self.assertEqual(pmb.opt_level, 2) # ensure default is level 2
|
||||||
|
pmb.opt_level = 3
|
||||||
|
self.assertEqual(pmb.opt_level, 3) # make sure it works
|
||||||
|
|
||||||
|
self.assertEqual(pmb.size_level, 0) # ensure default is level 0
|
||||||
|
pmb.size_level = 2
|
||||||
|
self.assertEqual(pmb.size_level, 2) # make sure it works
|
||||||
|
|
||||||
|
self.assertFalse(pmb.vectorize) # ensure default is False
|
||||||
|
pmb.vectorize = True
|
||||||
|
self.assertTrue(pmb.vectorize) # make sure it works
|
||||||
|
|
||||||
|
# make sure the default is False
|
||||||
|
self.assertFalse(pmb.disable_unit_at_a_time)
|
||||||
|
self.assertFalse(pmb.disable_unroll_loops)
|
||||||
|
if llvm.version <= (3, 3):
|
||||||
|
self.assertFalse(pmb.disable_simplify_lib_calls)
|
||||||
|
|
||||||
|
pmb.disable_unit_at_a_time = True
|
||||||
|
self.assertTrue(pmb.disable_unit_at_a_time)
|
||||||
|
|
||||||
|
# Do function pass
|
||||||
|
fpm = lp.FunctionPassManager.new(m)
|
||||||
|
pmb.populate(fpm)
|
||||||
|
fpm.run(fn_test1)
|
||||||
|
|
||||||
|
# Make sure test1 has changed
|
||||||
|
self.assertNotEqual(str(fn_test1).strip(), original_test1.strip())
|
||||||
|
|
||||||
|
# Do module pass
|
||||||
|
pm = lp.PassManager.new()
|
||||||
|
pmb.populate(pm)
|
||||||
|
pm.run(m)
|
||||||
|
|
||||||
|
# Make sure test2 has changed
|
||||||
|
self.assertNotEqual(str(fn_test2).strip(), original_test2.strip())
|
||||||
|
|
||||||
|
def test_dump_passes(self):
|
||||||
|
self.assertTrue(len(lp.PASSES)>0, msg="Cannot have no passes")
|
||||||
|
|
||||||
|
tests.append(TestPasses)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
28
llvm/tests/test_struct.py
Normal file
28
llvm/tests/test_struct.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Type, Module, Builder, Constant
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestStruct(TestCase):
|
||||||
|
def test_struct_identical(self):
|
||||||
|
ta = Type.struct([Type.int(32), Type.float()], name='ta')
|
||||||
|
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__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
685
llvm/tests/test_struct_args.py
Normal file
685
llvm/tests/test_struct_args.py
Normal file
|
|
@ -0,0 +1,685 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
from . import tests
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from ctypes import Structure, c_float, c_double, c_uint8, CFUNCTYPE
|
||||||
|
from llvm import core as lc
|
||||||
|
from llvm import ee as le
|
||||||
|
|
||||||
|
from .support import (skip_if_win32, skip_if_not_win32, skip_if_not_32bits,
|
||||||
|
skip_if_not_64bits, skip_if_not_intel_cpu, TestCase)
|
||||||
|
|
||||||
|
class TwoDoubleOneByte(Structure):
|
||||||
|
_fields_ = ('x', c_double), ('y', c_double), ('z', c_uint8)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<x=%f y=%f z=%d>' % (self.x, self.y, self.z)
|
||||||
|
|
||||||
|
class TwoDouble(Structure):
|
||||||
|
_fields_ = ('x', c_double), ('y', c_double)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<x=%f y=%f>' % (self.x, self.y)
|
||||||
|
|
||||||
|
class TwoFloat(Structure):
|
||||||
|
_fields_ = ('x', c_float), ('y', c_float)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<x=%f y=%f>' % (self.x, self.y)
|
||||||
|
|
||||||
|
class OneByte(Structure):
|
||||||
|
_fields_ = [('x', c_uint8)]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<x=%d>' % (self.x,)
|
||||||
|
|
||||||
|
@skip_if_not_intel_cpu
|
||||||
|
@skip_if_win32
|
||||||
|
class TestStructSystemVABI(TestCase):
|
||||||
|
'''
|
||||||
|
Non microsoft convention
|
||||||
|
'''
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# 64 bits
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_bigger_than_two_words_64(self):
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type, uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2, e3 = [builder.extract_value(arg, i) for i in range(3)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
ret = builder.insert_value(ret, e3, 2)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDoubleOneByte, TwoDoubleOneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDoubleOneByte(x=1.321321, y=6.54352, z=128)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
self.assertEqual(arg.z, ret.z)
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_just_two_words_64(self):
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type])
|
||||||
|
func_type = lc.Type.function(struct_type, [struct_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = func.args[0]
|
||||||
|
e1, e2 = [builder.extract_value(arg, i) for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
builder.ret(ret)
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDouble, TwoDouble)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDouble(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_two_halfwords(self):
|
||||||
|
'''Arguments smaller or equal to a word is packed into a word.
|
||||||
|
|
||||||
|
Passing as struct { float, float } occupies two XMM registers instead
|
||||||
|
of one.
|
||||||
|
The output must be in XMM.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
float_type = lc.Type.float()
|
||||||
|
struct_type = lc.Type.vector(float_type, 2)
|
||||||
|
func_type = lc.Type.function(struct_type, [struct_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = func.args[0]
|
||||||
|
constint = lambda x: lc.Constant.int(lc.Type.int(), x)
|
||||||
|
e1, e2 = [builder.extract_element(arg, constint(i))
|
||||||
|
for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_element(lc.Constant.undef(struct_type), se1,
|
||||||
|
constint(0))
|
||||||
|
ret = builder.insert_element(ret, se2, constint(1))
|
||||||
|
builder.ret(ret)
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoFloat, TwoFloat)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoFloat(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# 32 bits
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_structure_abi_32_1(self):
|
||||||
|
'''x86 is simple. Always pass structure as memory.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type, uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2, e3 = [builder.extract_value(arg, i) for i in range(3)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
ret = builder.insert_value(ret, e3, 2)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDoubleOneByte, TwoDoubleOneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDoubleOneByte(x=1.321321, y=6.54352, z=128)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
self.assertEqual(arg.z, ret.z)
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_structure_abi_32_2(self):
|
||||||
|
'''x86 is simple. Always pass structure as memory.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
float_type = lc.Type.float()
|
||||||
|
struct_type = lc.Type.struct([float_type, float_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2 = [builder.extract_value(arg, i) for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoFloat, TwoFloat)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoFloat(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_structure_abi_32_3(self):
|
||||||
|
'''x86 is simple. Always pass structure as memory.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1 = builder.extract_value(arg, 0)
|
||||||
|
se1 = builder.mul(e1, e1)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(OneByte, OneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = OneByte(x=8)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertEqual(arg.x * arg.x, ret.x)
|
||||||
|
|
||||||
|
tests.append(TestStructSystemVABI)
|
||||||
|
|
||||||
|
@skip_if_not_intel_cpu
|
||||||
|
@skip_if_not_win32
|
||||||
|
class TestStructMicrosoftABI(TestCase):
|
||||||
|
'''
|
||||||
|
Microsoft convention
|
||||||
|
'''
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# 64 bits
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_bigger_than_two_words_64(self):
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type, uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2, e3 = [builder.extract_value(arg, i) for i in range(3)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
ret = builder.insert_value(ret, e3, 2)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDoubleOneByte, TwoDoubleOneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDoubleOneByte(x=1.321321, y=6.54352, z=128)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
self.assertEqual(arg.z, ret.z)
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_just_two_words_64(self):
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2 = [builder.extract_value(arg, i) for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDouble, TwoDouble)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDouble(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
@skip_if_not_64bits
|
||||||
|
def test_two_halfwords(self):
|
||||||
|
'''Arguments smaller or equal to a word is packed into a word.
|
||||||
|
|
||||||
|
Floats structure are not passed on the XMM.
|
||||||
|
Treat it as a i64.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
float_type = lc.Type.float()
|
||||||
|
struct_type = lc.Type.struct([float_type, float_type])
|
||||||
|
abi_type = lc.Type.int(64)
|
||||||
|
|
||||||
|
func_type = lc.Type.function(abi_type, [abi_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = func.args[0]
|
||||||
|
|
||||||
|
struct_ptr = builder.alloca(struct_type)
|
||||||
|
struct_int_ptr = builder.bitcast(struct_ptr, lc.Type.pointer(abi_type))
|
||||||
|
builder.store(arg, struct_int_ptr)
|
||||||
|
|
||||||
|
arg = builder.load(struct_ptr)
|
||||||
|
|
||||||
|
e1, e2 = [builder.extract_value(arg, i) for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
|
||||||
|
builder.store(ret, struct_ptr)
|
||||||
|
ret = builder.load(struct_int_ptr)
|
||||||
|
|
||||||
|
builder.ret(ret)
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoFloat, TwoFloat)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoFloat(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
# 32 bits
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_one_word_register(self):
|
||||||
|
'''Argument is passed by memory.
|
||||||
|
Return value is passed by register.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(struct_type, [struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[0].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[0])
|
||||||
|
e1 = builder.extract_value(arg, 0)
|
||||||
|
se1 = builder.mul(e1, e1)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
|
||||||
|
builder.ret(ret)
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(OneByte, OneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = OneByte(x=8)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertEqual(arg.x * arg.x, ret.x)
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_two_floats(self):
|
||||||
|
'''Argument is passed by register.
|
||||||
|
Return in 2 registers
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
float_type = lc.Type.float()
|
||||||
|
struct_type = lc.Type.struct([float_type, float_type])
|
||||||
|
|
||||||
|
abi_type = lc.Type.int(64)
|
||||||
|
func_type = lc.Type.function(abi_type, [struct_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
out_ptr = builder.alloca(struct_type)
|
||||||
|
|
||||||
|
arg = func.args[0]
|
||||||
|
e1, e2 = [builder.extract_value(arg, i) for i in range(2)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
builder.store(ret, out_ptr)
|
||||||
|
|
||||||
|
out_int_ptr = builder.bitcast(out_ptr, lc.Type.pointer(abi_type))
|
||||||
|
|
||||||
|
builder.ret(builder.load(out_int_ptr))
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoFloat, TwoFloat)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoFloat(x=1.321321, y=6.54352)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
|
||||||
|
@skip_if_not_32bits
|
||||||
|
def test_bigger_than_two_words(self):
|
||||||
|
'''Pass in memory.
|
||||||
|
'''
|
||||||
|
m = lc.Module.new('test_struct_arg')
|
||||||
|
|
||||||
|
double_type = lc.Type.double()
|
||||||
|
uint8_type = lc.Type.int(8)
|
||||||
|
struct_type = lc.Type.struct([double_type, double_type, uint8_type])
|
||||||
|
struct_ptr_type = lc.Type.pointer(struct_type)
|
||||||
|
func_type = lc.Type.function(lc.Type.void(),
|
||||||
|
[struct_ptr_type, struct_ptr_type])
|
||||||
|
func = m.add_function(func_type, name='foo')
|
||||||
|
|
||||||
|
# return value pointer
|
||||||
|
func.args[0].add_attribute(lc.ATTR_STRUCT_RET)
|
||||||
|
|
||||||
|
# pass structure by value
|
||||||
|
func.args[1].add_attribute(lc.ATTR_BY_VAL)
|
||||||
|
|
||||||
|
# define function body
|
||||||
|
builder = lc.Builder.new(func.append_basic_block(''))
|
||||||
|
|
||||||
|
arg = builder.load(func.args[1])
|
||||||
|
e1, e2, e3 = [builder.extract_value(arg, i) for i in range(3)]
|
||||||
|
se1 = builder.fmul(e1, e2)
|
||||||
|
se2 = builder.fdiv(e1, e2)
|
||||||
|
ret = builder.insert_value(lc.Constant.undef(struct_type), se1, 0)
|
||||||
|
ret = builder.insert_value(ret, se2, 1)
|
||||||
|
ret = builder.insert_value(ret, e3, 2)
|
||||||
|
builder.store(ret, func.args[0])
|
||||||
|
builder.ret_void()
|
||||||
|
|
||||||
|
del builder
|
||||||
|
|
||||||
|
# verify
|
||||||
|
m.verify()
|
||||||
|
|
||||||
|
print(m)
|
||||||
|
# use with ctypes
|
||||||
|
engine = le.EngineBuilder.new(m).create()
|
||||||
|
ptr = engine.get_pointer_to_function(func)
|
||||||
|
|
||||||
|
cfunctype = CFUNCTYPE(TwoDoubleOneByte, TwoDoubleOneByte)
|
||||||
|
cfunc = cfunctype(ptr)
|
||||||
|
|
||||||
|
arg = TwoDoubleOneByte(x=1.321321, y=6.54352, z=128)
|
||||||
|
ret = cfunc(arg)
|
||||||
|
print(arg)
|
||||||
|
print(ret)
|
||||||
|
|
||||||
|
self.assertClose(arg.x * arg.y, ret.x)
|
||||||
|
self.assertClose(arg.x / arg.y, ret.y)
|
||||||
|
self.assertEqual(arg.z, ret.z)
|
||||||
|
|
||||||
|
tests.append(TestStructMicrosoftABI)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
36
llvm/tests/test_switch.py
Normal file
36
llvm/tests/test_switch.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import (Module, Type, Builder, Constant)
|
||||||
|
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestSwitch(TestCase):
|
||||||
|
def test_arg_attr(self):
|
||||||
|
m = Module.new('oifjda')
|
||||||
|
fnty = Type.function(Type.void(), [Type.int()])
|
||||||
|
func = m.add_function(fnty, 'foo')
|
||||||
|
bb = func.append_basic_block('')
|
||||||
|
bbdef = func.append_basic_block('')
|
||||||
|
bbsw1 = func.append_basic_block('')
|
||||||
|
bbsw2 = func.append_basic_block('')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
|
||||||
|
swt = bldr.switch(func.args[0], bbdef, n=2)
|
||||||
|
swt.add_case(Constant.int(Type.int(), 0), bbsw1)
|
||||||
|
swt.add_case(Constant.int(Type.int(), 1), bbsw2)
|
||||||
|
|
||||||
|
bldr.position_at_end(bbsw1)
|
||||||
|
bldr.ret_void()
|
||||||
|
|
||||||
|
bldr.position_at_end(bbsw2)
|
||||||
|
bldr.ret_void()
|
||||||
|
|
||||||
|
bldr.position_at_end(bbdef)
|
||||||
|
bldr.ret_void()
|
||||||
|
|
||||||
|
func.verify()
|
||||||
|
|
||||||
|
tests.append(TestSwitch)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
62
llvm/tests/test_target_machines.py
Normal file
62
llvm/tests/test_target_machines.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import unittest
|
||||||
|
import llvm.core as lc
|
||||||
|
import llvm.ee as le
|
||||||
|
from llvm.core import Type, Builder
|
||||||
|
from .support import TestCase, tests, skip_if
|
||||||
|
|
||||||
|
# Check PTX backend
|
||||||
|
if le.initialize_target('PTX', noraise=True):
|
||||||
|
PTX_ARCH = 'ptx64'
|
||||||
|
elif le.initialize_target('NVPTX', noraise=True):
|
||||||
|
PTX_ARCH = 'nvptx64'
|
||||||
|
else:
|
||||||
|
PTX_ARCH = None
|
||||||
|
|
||||||
|
class TestTargetMachines(TestCase):
|
||||||
|
'''Exercise target machines
|
||||||
|
|
||||||
|
Require PTX backend
|
||||||
|
'''
|
||||||
|
def test_native(self):
|
||||||
|
m, _ = self._build_module()
|
||||||
|
tm = le.EngineBuilder.new(m).select_target()
|
||||||
|
|
||||||
|
self.assertTrue(tm.target_name)
|
||||||
|
self.assertTrue(tm.target_data)
|
||||||
|
self.assertTrue(tm.target_short_description)
|
||||||
|
self.assertTrue(tm.triple)
|
||||||
|
self.assertIn('foo', tm.emit_assembly(m))
|
||||||
|
self.assertTrue(le.get_host_cpu_name())
|
||||||
|
|
||||||
|
@skip_if(not PTX_ARCH, msg='LLVM is not compiled with PTX enabled')
|
||||||
|
def test_ptx(self):
|
||||||
|
arch = PTX_ARCH
|
||||||
|
print(arch)
|
||||||
|
m, func = self._build_module()
|
||||||
|
func.calling_convention = lc.CC_PTX_KERNEL # set calling conv
|
||||||
|
ptxtm = le.TargetMachine.lookup(arch=arch, cpu='sm_20')
|
||||||
|
self.assertTrue(ptxtm.triple)
|
||||||
|
self.assertTrue(ptxtm.cpu)
|
||||||
|
ptxasm = ptxtm.emit_assembly(m)
|
||||||
|
self.assertIn('foo', ptxasm)
|
||||||
|
if arch == 'nvptx64':
|
||||||
|
self.assertIn('.address_size 64', ptxasm)
|
||||||
|
self.assertIn('sm_20', ptxasm)
|
||||||
|
|
||||||
|
def _build_module(self):
|
||||||
|
m = lc.Module.new('TestTargetMachines')
|
||||||
|
|
||||||
|
fnty = Type.function(Type.void(), [])
|
||||||
|
func = m.add_function(fnty, name='foo')
|
||||||
|
|
||||||
|
bldr = Builder.new(func.append_basic_block('entry'))
|
||||||
|
bldr.ret_void()
|
||||||
|
m.verify()
|
||||||
|
return m, func
|
||||||
|
|
||||||
|
|
||||||
|
tests.append(TestTargetMachines)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
30
llvm/tests/test_type_hash.py
Normal file
30
llvm/tests/test_type_hash.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Type
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestTypeHash(TestCase):
|
||||||
|
def test_scalar_type(self):
|
||||||
|
i32a = Type.int(32)
|
||||||
|
i32b = Type.int(32)
|
||||||
|
i64a = Type.int(64)
|
||||||
|
i64b = Type.int(64)
|
||||||
|
ts = set([i32a, i32b, i64a, i64b])
|
||||||
|
self.assertTrue(len(ts))
|
||||||
|
self.assertTrue(i32a in ts)
|
||||||
|
self.assertTrue(i64b in ts)
|
||||||
|
|
||||||
|
def test_struct_type(self):
|
||||||
|
ta = Type.struct([Type.int(32), Type.float()])
|
||||||
|
tb = Type.struct([Type.int(32), Type.float()])
|
||||||
|
tc = Type.struct([Type.int(32), Type.int(32), Type.float()])
|
||||||
|
ts = set([ta, tb, tc])
|
||||||
|
self.assertTrue(len(ts) == 2)
|
||||||
|
self.assertTrue(ta in ts)
|
||||||
|
self.assertTrue(tb in ts)
|
||||||
|
self.assertTrue(tc in ts)
|
||||||
|
|
||||||
|
tests.append(TestTypeHash)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
43
llvm/tests/test_uses.py
Normal file
43
llvm/tests/test_uses.py
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type, Builder, Constant
|
||||||
|
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestUses(TestCase):
|
||||||
|
|
||||||
|
def test_uses(self):
|
||||||
|
m = Module.new('a')
|
||||||
|
t = Type.int()
|
||||||
|
ft = Type.function(t, [t, t, t])
|
||||||
|
f = m.add_function(ft, "func")
|
||||||
|
b = f.append_basic_block('entry')
|
||||||
|
bld = Builder.new(b)
|
||||||
|
tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1")
|
||||||
|
tmp2 = bld.add(tmp1, f.args[1], "tmp2")
|
||||||
|
tmp3 = bld.add(tmp1, f.args[2], "tmp3")
|
||||||
|
bld.ret(tmp3)
|
||||||
|
|
||||||
|
# Testing use count
|
||||||
|
self.assertEqual(f.args[0].use_count, 1)
|
||||||
|
self.assertEqual(f.args[1].use_count, 1)
|
||||||
|
self.assertEqual(f.args[2].use_count, 1)
|
||||||
|
self.assertEqual(tmp1.use_count, 2)
|
||||||
|
self.assertEqual(tmp2.use_count, 0)
|
||||||
|
self.assertEqual(tmp3.use_count, 1)
|
||||||
|
|
||||||
|
# Testing uses
|
||||||
|
self.assert_(f.args[0].uses[0] is tmp1)
|
||||||
|
self.assertEqual(len(f.args[0].uses), 1)
|
||||||
|
self.assert_(f.args[1].uses[0] is tmp2)
|
||||||
|
self.assertEqual(len(f.args[1].uses), 1)
|
||||||
|
self.assert_(f.args[2].uses[0] is tmp3)
|
||||||
|
self.assertEqual(len(f.args[2].uses), 1)
|
||||||
|
self.assertEqual(len(tmp1.uses), 2)
|
||||||
|
self.assertEqual(len(tmp2.uses), 0)
|
||||||
|
self.assertEqual(len(tmp3.uses), 1)
|
||||||
|
|
||||||
|
tests.append(TestUses)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
59
llvm/tests/test_volatile.py
Normal file
59
llvm/tests/test_volatile.py
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import unittest
|
||||||
|
from llvm.core import Module, Type, Builder
|
||||||
|
from .support import TestCase, tests
|
||||||
|
|
||||||
|
class TestVolatile(TestCase):
|
||||||
|
|
||||||
|
def test_volatile(self):
|
||||||
|
mod = Module.new('mod')
|
||||||
|
functype = Type.function(Type.void(), [])
|
||||||
|
func = mod.add_function(functype, name='foo')
|
||||||
|
bb = func.append_basic_block('entry')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
ptr = bldr.alloca(Type.int())
|
||||||
|
|
||||||
|
# test load inst
|
||||||
|
val = bldr.load(ptr)
|
||||||
|
self.assertFalse(val.is_volatile, "default must be non-volatile")
|
||||||
|
val.set_volatile(True)
|
||||||
|
self.assertTrue(val.is_volatile, "fail to set volatile")
|
||||||
|
val.set_volatile(False)
|
||||||
|
self.assertFalse(val.is_volatile, "fail to unset volatile")
|
||||||
|
|
||||||
|
# test store inst
|
||||||
|
store_inst = bldr.store(val, ptr)
|
||||||
|
self.assertFalse(store_inst.is_volatile, "default must be non-volatile")
|
||||||
|
store_inst.set_volatile(True)
|
||||||
|
self.assertTrue(store_inst.is_volatile, "fail to set volatile")
|
||||||
|
store_inst.set_volatile(False)
|
||||||
|
self.assertFalse(store_inst.is_volatile, "fail to unset volatile")
|
||||||
|
|
||||||
|
def test_volatile_another(self):
|
||||||
|
mod = Module.new('mod')
|
||||||
|
functype = Type.function(Type.void(), [])
|
||||||
|
func = mod.add_function(functype, name='foo')
|
||||||
|
bb = func.append_basic_block('entry')
|
||||||
|
bldr = Builder.new(bb)
|
||||||
|
ptr = bldr.alloca(Type.int())
|
||||||
|
|
||||||
|
# test load inst
|
||||||
|
val = bldr.load(ptr, volatile=True)
|
||||||
|
self.assertTrue(val.is_volatile, "volatile kwarg does not work")
|
||||||
|
val.set_volatile(False)
|
||||||
|
self.assertFalse(val.is_volatile, "fail to unset volatile")
|
||||||
|
val.set_volatile(True)
|
||||||
|
self.assertTrue(val.is_volatile, "fail to set volatile")
|
||||||
|
|
||||||
|
# test store inst
|
||||||
|
store_inst = bldr.store(val, ptr, volatile=True)
|
||||||
|
self.assertTrue(store_inst.is_volatile, "volatile kwarg does not work")
|
||||||
|
store_inst.set_volatile(False)
|
||||||
|
self.assertFalse(store_inst.is_volatile, "fail to unset volatile")
|
||||||
|
store_inst.set_volatile(True)
|
||||||
|
self.assertTrue(store_inst.is_volatile, "fail to set volatile")
|
||||||
|
|
||||||
|
tests.append(TestVolatile)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
0
llvm/utils/__init__.py
Normal file
0
llvm/utils/__init__.py
Normal file
181
llvm/utils/check_intrinsics.py
Normal file
181
llvm/utils/check_intrinsics.py
Normal 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:])
|
||||||
|
|
@ -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'):
|
def detect_avx_support(option='detect'):
|
||||||
'''Detect AVX support'''
|
'''Detect AVX support'''
|
||||||
|
|
@ -36,13 +40,25 @@ def detect_unix_like():
|
||||||
except IOError:
|
except IOError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for line in info:
|
with contextlib.closing(info):
|
||||||
if line.lstrip().startswith('flags'):
|
for line in info:
|
||||||
features = line.split()
|
if line.lstrip().startswith('flags'):
|
||||||
if 'avx' in features and 'xsave' in features:
|
features = line.split()
|
||||||
# enable AVX if flags contain AVX
|
if 'avx' in features and 'xsave' in features:
|
||||||
return True
|
# enable AVX if flags contain AVX
|
||||||
return False
|
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():
|
def detect_osx_like():
|
||||||
try:
|
try:
|
||||||
|
|
@ -51,9 +67,10 @@ def detect_osx_like():
|
||||||
except OSError:
|
except OSError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
features = info.stdout.read()
|
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__':
|
||||||
|
|
|
||||||
2
llvm_array/__init__.py
Normal file
2
llvm_array/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from .array import *
|
||||||
257
llvm_array/array.py
Normal file
257
llvm_array/array.py
Normal file
|
|
@ -0,0 +1,257 @@
|
||||||
|
# This should be moved to llvmpy
|
||||||
|
#
|
||||||
|
# There are different array kinds parameterized by eltype and nd
|
||||||
|
#
|
||||||
|
# Contiguous or Fortran
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# intp shape[nd];
|
||||||
|
# } contiguous_array(eltype, nd)
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# diminfo shape[nd];
|
||||||
|
# } strided_array(eltype, nd)
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# intp shape[nd];
|
||||||
|
# intp stride[nd];
|
||||||
|
# } strided_soa_array(eltype, nd)
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# intp dim;
|
||||||
|
# intp stride;
|
||||||
|
#} diminfo
|
||||||
|
#
|
||||||
|
# These are for low-level array-routines that need to know the number
|
||||||
|
# of dimensions at run-time (not just code-generation time):
|
||||||
|
#
|
||||||
|
# The first two are recommended
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# intp shape[nd];
|
||||||
|
# } contiguous_array_nd(eltype)
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# diminfo shape[nd];
|
||||||
|
# } strided_array_nd(eltype)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Backward compatible but deprecated:
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int32 nd;
|
||||||
|
# intp shape[nd];
|
||||||
|
# intp stride[nd];
|
||||||
|
# } strided_soa_array_nd(eltype)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The most general (where the kind of array is stored as well as number
|
||||||
|
# of dimensions)
|
||||||
|
# Rarely needed.
|
||||||
|
#
|
||||||
|
# struct {
|
||||||
|
# eltype *data;
|
||||||
|
# int16 nd;
|
||||||
|
# int16 dimkind;
|
||||||
|
# ???
|
||||||
|
# } array_nd(eltype)
|
||||||
|
#
|
||||||
|
# where ??? is run-time interpreted based on the dimkind to either:
|
||||||
|
# intp shape[nd]; for dimkind = C_CONTIGUOUS or F_CONTIGUOUS
|
||||||
|
#
|
||||||
|
# diminfo shape[nd]; for dimkind = STRIDED
|
||||||
|
#
|
||||||
|
# intp shape[ind];
|
||||||
|
# intp strides[ind]; dimkind = STRIDED_SOA
|
||||||
|
#
|
||||||
|
|
||||||
|
import llvm.core as lc
|
||||||
|
from llvm.core import Type
|
||||||
|
import llvm_cbuilder.shortnames as C
|
||||||
|
|
||||||
|
# Different Array Types
|
||||||
|
ARRAYBIT = 1<<4
|
||||||
|
C_CONTIGUOUS = ARRAYBIT + 0
|
||||||
|
F_CONTIGUOUS = ARRAYBIT + 1
|
||||||
|
STRIDED = ARRAYBIT + 2
|
||||||
|
STRIDED_SOA = ARRAYBIT + 3
|
||||||
|
|
||||||
|
HAS_ND = 1<<5
|
||||||
|
C_CONTIGUOUS_ND = C_CONTIGUOUS + HAS_ND
|
||||||
|
F_CONTIGUOUS_ND = F_CONTIGUOUS + HAS_ND
|
||||||
|
STRIDED_ND = STRIDED + HAS_ND
|
||||||
|
STRIDED_SOA_ND = STRIDED_SOA + HAS_ND
|
||||||
|
|
||||||
|
HAS_DIMKIND = 1<<6
|
||||||
|
C_CONTIGUOUS_DK = C_CONTIGUOUS + HAS_DIMKIND
|
||||||
|
F_CONTIGUOUS_DK = F_CONTIGUOUS + HAS_DIMKIND
|
||||||
|
STRIDED_DK = STRIDED + HAS_DIMKIND
|
||||||
|
STRIDED_SOA_DK = STRIDED_SOA + HAS_DIMKIND
|
||||||
|
|
||||||
|
array_kinds = (C_CONTIGUOUS, F_CONTIGUOUS, STRIDED, STRIDED_SOA,
|
||||||
|
C_CONTIGUOUS_ND, F_CONTIGUOUS_ND, STRIDED_ND, STRIDED_SOA_DK,
|
||||||
|
C_CONTIGUOUS_DK, F_CONTIGUOUS_DK, STRIDED_DK, STRIDED_SOA_DK)
|
||||||
|
|
||||||
|
_invmap = {}
|
||||||
|
|
||||||
|
def kind_to_str(kind):
|
||||||
|
global _invmap
|
||||||
|
if not _invmap:
|
||||||
|
for key, value in globals().items():
|
||||||
|
if isinstance(value, int) and value in array_kinds:
|
||||||
|
_invmap[value] = key
|
||||||
|
return _invmap[kind]
|
||||||
|
|
||||||
|
def str_to_kind(str):
|
||||||
|
trial = eval(str)
|
||||||
|
if trial not in array_kinds:
|
||||||
|
raise ValueError("Invalid Array Kind")
|
||||||
|
return trial
|
||||||
|
|
||||||
|
void_type = C.void
|
||||||
|
int32_type = C.int32
|
||||||
|
char_type = C.char
|
||||||
|
int16_type = C.int16
|
||||||
|
intp_type = C.intp
|
||||||
|
|
||||||
|
diminfo_type = Type.struct([intp_type, # shape
|
||||||
|
intp_type # stride
|
||||||
|
], name='diminfo')
|
||||||
|
|
||||||
|
_cache = {}
|
||||||
|
# This is the way we define LLVM arrays.
|
||||||
|
# CONTIGUOUS and STRIDED are strongly encouraged...
|
||||||
|
def array_type(nd, kind, el_type=char_type):
|
||||||
|
key = (kind, nd, el_type)
|
||||||
|
if _cache.has_key(key):
|
||||||
|
return _cache[key]
|
||||||
|
|
||||||
|
base = kind & (~(HAS_ND | HAS_DIMKIND))
|
||||||
|
if base == C_CONTIGUOUS:
|
||||||
|
dimstr = 'Array_C'
|
||||||
|
elif base == F_CONTIGUOUS:
|
||||||
|
dimstr = 'Array_F'
|
||||||
|
elif base == STRIDED:
|
||||||
|
dimstr = 'Array_S'
|
||||||
|
elif base == STRIDED_SOA:
|
||||||
|
dimstr = 'Array_A'
|
||||||
|
else:
|
||||||
|
raise TypeError("Do not understand Array kind of %d" % kind)
|
||||||
|
|
||||||
|
terms = [Type.pointer(el_type)] # data
|
||||||
|
|
||||||
|
if (kind & HAS_ND):
|
||||||
|
terms.append(int32_type) # nd
|
||||||
|
dimstr += '_ND'
|
||||||
|
elif (kind & HAS_DIMKIND):
|
||||||
|
terms.extend([int16_type, int16_type]) # nd, dimkind
|
||||||
|
dimstr += '_DK'
|
||||||
|
|
||||||
|
if base in [C_CONTIGUOUS, F_CONTIGUOUS]:
|
||||||
|
terms.append(Type.array(intp_type, nd)) # shape
|
||||||
|
elif base == STRIDED:
|
||||||
|
terms.append(Type.array(diminfo_type, nd)) # diminfo
|
||||||
|
elif base == STRIDED_SOA:
|
||||||
|
terms.extend([Type.array(intp_type, nd), # shape
|
||||||
|
Type.array(intp_type, nd)]) # strides
|
||||||
|
|
||||||
|
ret = Type.struct(terms, name=dimstr)
|
||||||
|
_cache[key] = ret
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def check_array(arrtyp):
|
||||||
|
if not isinstance(arrtyp, lc.StructType):
|
||||||
|
return None
|
||||||
|
if arrtyp.element_count not in [2, 3, 4, 5]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Look through _cache and see if it's there
|
||||||
|
for key, value in _cache.items():
|
||||||
|
if arrtyp is value:
|
||||||
|
return key
|
||||||
|
|
||||||
|
return _raw_check_array(arrtyp)
|
||||||
|
|
||||||
|
# Manual check
|
||||||
|
def _raw_check_array(arrtyp):
|
||||||
|
a0 = arrtyp.elements[0]
|
||||||
|
a1 = arrtyp.elements[1]
|
||||||
|
if not isinstance(a0, lc.PointerType) or \
|
||||||
|
not (isinstance(a1, lc.ArrayType) or
|
||||||
|
(a1 == int32_type) or (a1 == int16_type)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
data_type = a0.pointee
|
||||||
|
|
||||||
|
if arrtyp.is_literal:
|
||||||
|
c_contig = True
|
||||||
|
else:
|
||||||
|
if arrtyp.name.startswith('Array_F'):
|
||||||
|
c_contig = False
|
||||||
|
else:
|
||||||
|
c_contig = True
|
||||||
|
|
||||||
|
|
||||||
|
if a1 == int32_type:
|
||||||
|
num = 2
|
||||||
|
strided = STRIDED_ND
|
||||||
|
strided_soa = STRIDED_SOA_ND
|
||||||
|
c_contiguous = C_CONTIGUOUS_ND
|
||||||
|
f_contiguous = F_CONTIGUOUS_ND
|
||||||
|
elif a1 == int16_type:
|
||||||
|
if arrtyp.element_count < 3 or arrtyp.elements[2] != int16_type:
|
||||||
|
return None
|
||||||
|
num = 3
|
||||||
|
strided = STRIDED_DK
|
||||||
|
strided_soa = STRIDED_SOA_DK
|
||||||
|
c_contiguous = C_CONTIGUOUS_DK
|
||||||
|
f_contiguous = F_CONTIGUOUS_DK
|
||||||
|
else:
|
||||||
|
num = 1
|
||||||
|
strided = STRIDED
|
||||||
|
strided_soa = STRIDED_SOA
|
||||||
|
c_contiguous = C_CONTIGUOUS
|
||||||
|
f_contiguous = F_CONTIGUOUS
|
||||||
|
|
||||||
|
elcount = num + 2
|
||||||
|
# otherwise we have lc.ArrType as element [1]
|
||||||
|
if arrtyp.element_count not in [num+1,num+2]:
|
||||||
|
return None
|
||||||
|
s1 = arrtyp.elements[num]
|
||||||
|
nd = s1.count
|
||||||
|
|
||||||
|
if arrtyp.element_count == elcount:
|
||||||
|
if not isinstance(arrtyp.elements[num+1], lc.ArrayType):
|
||||||
|
return None
|
||||||
|
s2 = arrtyp.elements[num+1]
|
||||||
|
if s1.element != intp_type or s2.element != intp_type:
|
||||||
|
return None
|
||||||
|
if s1.count != s2.count:
|
||||||
|
return None
|
||||||
|
return strided_soa, nd, data_type
|
||||||
|
|
||||||
|
if s1.element == diminfo_type:
|
||||||
|
return strided, nd, data_type
|
||||||
|
elif s1.element == intp_type:
|
||||||
|
return c_contiguous if c_contig else f_contiguous, nd, data_type
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
arr = array_type(5, C_CONTIGUOUS)
|
||||||
|
assert check_array(arr) == (C_CONTIGUOUS, 5, char_type)
|
||||||
|
arr = array_type(4, STRIDED)
|
||||||
|
assert check_array(arr) == (STRIDED, 4, char_type)
|
||||||
|
arr = array_type(3, STRIDED_SOA)
|
||||||
|
assert check_array(arr) == (STRIDED_SOA, 3, char_type)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
||||||
|
|
@ -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_array(ty, count, name=name)
|
ptr = self.builder.alloca(ty, size=count, name=name)
|
||||||
return CArray(self, ptr)
|
return CArray(self, ptr)
|
||||||
|
|
||||||
def ret(self, val=None):
|
def ret(self, val=None):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# README
|
|
||||||
|
|
||||||
This is a reimplementation of the LLVM binding, aiming to provide a more familiar interface to the C++ API whenever possible.
|
|
||||||
|
|
||||||
The implementation uses a custom DSL in python to describe the interface (under binding directory). The DSL serves as input to *gen.py* for generation of the .cpp and .py files for the actual binding.
|
|
||||||
151
llvmpy/README.md
Normal file
151
llvmpy/README.md
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
# README
|
||||||
|
|
||||||
|
This is a reimplementation of the LLVM binding, aiming to provide a more
|
||||||
|
familiar interface to the C++ API whenever possible.
|
||||||
|
|
||||||
|
The implementation uses a custom DSL in python to describe the interface.
|
||||||
|
The DSL serves as input to *gen/gen.py* for generation of the .cpp and .py files
|
||||||
|
for the actual binding.
|
||||||
|
|
||||||
|
# How to Add New Class
|
||||||
|
|
||||||
|
Let's use the `llvm::Module` as an example because it should be one of the most
|
||||||
|
familiar class in LLVM.
|
||||||
|
|
||||||
|
Reference code in https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Module.py
|
||||||
|
and see LLVM documentation at http://llvm.org/docs/doxygen/html/classllvm_1_1Module.html
|
||||||
|
|
||||||
|
1) Import binding helpers
|
||||||
|
|
||||||
|
```python
|
||||||
|
from binding import *
|
||||||
|
# Yes, it is bad practice to import star.
|
||||||
|
# I will fix it one day.
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Import LLVM namespace
|
||||||
|
|
||||||
|
```python
|
||||||
|
from .namespace import llvm
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Declare the class
|
||||||
|
|
||||||
|
```python
|
||||||
|
Module = llvm.Class()
|
||||||
|
```
|
||||||
|
|
||||||
|
4) Import all the dependencies for the definition
|
||||||
|
|
||||||
|
5) Define the class
|
||||||
|
|
||||||
|
```python
|
||||||
|
@Module
|
||||||
|
class Module:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Inside the definition...
|
||||||
|
|
||||||
|
5.1) Use the ``_include_`` attribute to add include files.
|
||||||
|
|
||||||
|
5.2) Use ``Enum`` to create an enumerator type.
|
||||||
|
|
||||||
|
5.3) Make constructor
|
||||||
|
|
||||||
|
Not every class needs to have a binding for the constructor.
|
||||||
|
Only add things that will be used.
|
||||||
|
|
||||||
|
```python
|
||||||
|
new = Constructor(cast(str, StringRef), ref(LLVMContext))
|
||||||
|
```
|
||||||
|
|
||||||
|
The constructor must be named as "new".
|
||||||
|
|
||||||
|
The args to ``Constructor`` are parameters of the signature.
|
||||||
|
The first parameter means cast Python string to a StringRef.
|
||||||
|
The second parameter means pass LLVMContext object as a value reference.
|
||||||
|
|
||||||
|
5.4) Make destructor
|
||||||
|
|
||||||
|
Not every class needs to have a binding for the destructor.
|
||||||
|
Only add things that will be used.
|
||||||
|
If it is always owned by another object, it usually does not need to have one.
|
||||||
|
|
||||||
|
```python
|
||||||
|
delete = Destructor()
|
||||||
|
```
|
||||||
|
|
||||||
|
The destructor must be named as "delete".
|
||||||
|
|
||||||
|
5.5) Add Simple Methods
|
||||||
|
|
||||||
|
```python
|
||||||
|
getFunction = Method(ptr(Function), cast(str, StringRef))
|
||||||
|
```
|
||||||
|
|
||||||
|
The first arg is the return type: a ponter to Function.
|
||||||
|
The rest of the args are for the parameters.
|
||||||
|
|
||||||
|
Note: ``cast(fromtype, totype)`` can be used as return-type as well.
|
||||||
|
In that case, the ``fromtype`` will usually refer to a LLVM object
|
||||||
|
and the ``totype`` will refer to the Python object.
|
||||||
|
|
||||||
|
5.6) Add custom methods defined in C++
|
||||||
|
|
||||||
|
The ``list_functions`` is created as a ``CustomMethod``.
|
||||||
|
|
||||||
|
```python
|
||||||
|
list_functions = CustomMethod('Module_list_functions', PyObjectPtr)
|
||||||
|
```
|
||||||
|
|
||||||
|
The first arg is the name that appears in C++.
|
||||||
|
The second argument is the return-type.
|
||||||
|
The rest of the arguments are parameters.
|
||||||
|
|
||||||
|
The definition of ``Module_list_functions`` is located in
|
||||||
|
"include/llvm_binding/extra.h".
|
||||||
|
|
||||||
|
5.7) Add custom python method
|
||||||
|
|
||||||
|
One can also add custom methods in Python, e.g. ``__str__``.
|
||||||
|
|
||||||
|
```python
|
||||||
|
@CustomPythonMethod
|
||||||
|
def __str__(self):
|
||||||
|
from llvmpy import extra
|
||||||
|
os = extra.make_raw_ostream_for_printing()
|
||||||
|
self.print_(os, None)
|
||||||
|
return os.str()
|
||||||
|
```
|
||||||
|
|
||||||
|
The body of ``__str__`` is directly copied to the Python output file.
|
||||||
|
Thus, it can't reference to anything in current file scope.
|
||||||
|
|
||||||
|
# Static Methods
|
||||||
|
|
||||||
|
``StaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/PassRegistry.py
|
||||||
|
|
||||||
|
``CustomStaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/TargetRegistry.py
|
||||||
|
|
||||||
|
|
||||||
|
# Namespace
|
||||||
|
|
||||||
|
``Namespace`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/CodeGen.py
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
|
||||||
|
``Function`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Assembly/Parser.py
|
||||||
|
|
||||||
|
``CustomFunction`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Bitcode/ReaderWriter.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Other Things from the binding.py
|
||||||
|
|
||||||
|
https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py
|
||||||
|
|
||||||
|
The list of C++ types: https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py#L218
|
||||||
|
|
||||||
|
|
@ -1,55 +1,95 @@
|
||||||
#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* getName(PyObject* self, PyObject* args) {
|
PyObject* GetAPIModule(){
|
||||||
PyObject* obj;
|
if (NULL == TheAPIModule)
|
||||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
TheAPIModule = PyImport_ImportModule("llvmpy._api");
|
||||||
return NULL;
|
return TheAPIModule;
|
||||||
}
|
|
||||||
const char* name = PyCapsule_GetName(obj);
|
|
||||||
if (!name) return NULL;
|
|
||||||
|
|
||||||
return PyString_FromString(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* getPointer(PyObject* self, PyObject* args) {
|
PyObject* GetCapsuleModule(){
|
||||||
PyObject* obj;
|
if (NULL == TheCapsuleModule)
|
||||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
TheCapsuleModule = PyImport_ImportModule("llvmpy.capsule");
|
||||||
return NULL;
|
return TheCapsuleModule;
|
||||||
}
|
|
||||||
void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj));
|
|
||||||
if (!pointer) return NULL;
|
|
||||||
|
|
||||||
return PyLong_FromVoidPtr(pointer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* check(PyObject* self, PyObject* args) {
|
PyObject* GetCapsuleClass() {
|
||||||
PyObject* obj;
|
if (NULL == TheCapsuleClass)
|
||||||
if (!PyArg_ParseTuple(args, "O", &obj)){
|
TheCapsuleClass = PyObject_GetAttrString(GetCapsuleModule(),
|
||||||
return NULL;
|
"Capsule");
|
||||||
}
|
return TheCapsuleClass;
|
||||||
if (PyCapsule_CheckExact(obj)) {
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
} else {
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------
|
static
|
||||||
// PyCapsule Context
|
PyObject* GetWrapperClass() {
|
||||||
// ------------------
|
if (NULL == TheWrapperClass)
|
||||||
|
TheWrapperClass = PyObject_GetAttrString(GetCapsuleModule(),
|
||||||
|
"Wrapper");
|
||||||
|
return TheWrapperClass;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
CapsuleContext* getContext(PyObject* self, PyObject* args) {
|
PyObject* GetCache() {
|
||||||
PyObject* obj;
|
if (NULL == TheCache)
|
||||||
if (!PyArg_ParseTuple(args, "O", &obj)) {
|
TheCache = PyObject_GetAttrString(GetCapsuleModule(), "_cache");
|
||||||
return NULL;
|
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);
|
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.");
|
||||||
|
|
@ -59,9 +99,8 @@ CapsuleContext* getContext(PyObject* self, PyObject* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* getClassName(PyObject* self, PyObject* args) {
|
PyObject* GetClassName(PyObject* obj) {
|
||||||
CapsuleContext* context = getContext(self, args);
|
CapsuleContext* context = GetContext(obj);
|
||||||
//Assert(context->_magic == 0xdead);
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} 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[] = {
|
static PyMethodDef core_methods[] = {
|
||||||
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
|
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
|
||||||
|
|
@ -76,6 +585,10 @@ 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
|
||||||
};
|
};
|
||||||
|
|
@ -106,10 +619,21 @@ 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 PY_MAJOR_VERSION >= 3
|
}
|
||||||
|
|
||||||
|
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;
|
return module;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,27 @@
|
||||||
from weakref import WeakKeyDictionary, WeakValueDictionary, ref
|
from weakref import WeakValueDictionary
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
def set_debug(enabled):
|
||||||
'''
|
'''
|
||||||
Side-effect: configure logger with it is not configured.
|
Side-effect: configure logger with it is not configured.
|
||||||
|
|
@ -17,75 +36,63 @@ 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:
|
|
||||||
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 Capsule.getClassName(self.capsule)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return Capsule.getName(self.capsule)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pointer(self):
|
|
||||||
return Capsule.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 = {}
|
||||||
|
|
||||||
|
|
@ -93,15 +100,16 @@ _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 = Capsule.getPointer(old)
|
addr = getPointer(old)
|
||||||
name = Capsule.getName(old)
|
name = getName(old)
|
||||||
if _addr2dtor.get((name, addr)) is None:
|
if _addr2dtor.get((name, addr)) is None:
|
||||||
clsname = Capsule.getClassName(old)
|
clsname = 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
|
||||||
|
|
||||||
|
|
@ -111,60 +119,86 @@ 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[addr] is None
|
assert _addr2dtor[(name, 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 wrap(cap, owned=False):
|
#def has_ownership(cap):
|
||||||
'''Wrap a PyCapsule with the corresponding Wrapper class.
|
# addr = Capsule.getPointer(cap)
|
||||||
If `cap` is not a PyCapsule, returns `cap`
|
# name = Capsule.getName(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
|
|
||||||
try: # lookup cached object
|
|
||||||
return _cache[cls][addr]
|
|
||||||
except KeyError:
|
|
||||||
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.
|
'''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
|
||||||
|
|
@ -177,10 +211,11 @@ class Wrapper(object):
|
||||||
return hash(self._capsule)
|
return hash(self._capsule)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self._capsule == other._capsule
|
if isinstance(other, Wrapper):
|
||||||
|
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)
|
||||||
|
|
@ -189,25 +224,25 @@ 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('::', '_')
|
|
||||||
try:
|
|
||||||
caster = getattr(_api.downcast, fname)
|
|
||||||
except AttributeError:
|
|
||||||
fmt = "Downcast from %s to %s is not supported"
|
|
||||||
raise TypeError(fmt % (fromty, toty))
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import inspect, textwrap
|
import inspect, textwrap
|
||||||
import functools
|
|
||||||
import codegen as cg
|
import codegen as cg
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
@ -8,10 +7,12 @@ 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 = []
|
||||||
|
|
@ -247,7 +248,8 @@ class Class(SubModule, _Type):
|
||||||
def __call__(self, defn):
|
def __call__(self, defn):
|
||||||
assert not self._is_defined
|
assert not self._is_defined
|
||||||
# process the definition in "defn"
|
# process the definition in "defn"
|
||||||
self.name = defn.__name__
|
self.name = getattr(defn, '_name_', defn.__name__)
|
||||||
|
|
||||||
for k, v in defn.__dict__.items():
|
for k, v in defn.__dict__.items():
|
||||||
if isinstance(v, Method):
|
if isinstance(v, Method):
|
||||||
self.methods.append(v)
|
self.methods.append(v)
|
||||||
|
|
@ -292,6 +294,10 @@ 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:
|
||||||
|
|
@ -332,7 +338,7 @@ class Class(SubModule, _Type):
|
||||||
writer.die_if_false(raw, verbose=name)
|
writer.die_if_false(raw, verbose=name)
|
||||||
ptrty = ptr(self).fullname
|
ptrty = ptr(self).fullname
|
||||||
ty = self.fullname
|
ty = self.fullname
|
||||||
fmt = 'typecast< %(ty)s >::from(%(raw)s)'
|
fmt = 'unwrap_as<%(ty)s, %(name)s >::from(%(raw)s)'
|
||||||
casted = writer.declare(ptrty, fmt % locals())
|
casted = writer.declare(ptrty, fmt % locals())
|
||||||
writer.die_if_false(casted)
|
writer.die_if_false(casted)
|
||||||
return casted
|
return casted
|
||||||
|
|
@ -398,6 +404,7 @@ 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'
|
||||||
|
|
||||||
|
|
@ -515,6 +522,7 @@ 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)
|
||||||
|
|
@ -593,6 +601,7 @@ 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'
|
||||||
|
|
||||||
|
|
@ -624,6 +633,7 @@ 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)
|
||||||
|
|
@ -685,13 +695,16 @@ 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'
|
||||||
|
|
||||||
|
|
@ -756,6 +769,7 @@ 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')
|
||||||
|
|
@ -844,6 +858,7 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,8 @@ class CppCodeWriter(CodeWriterBase):
|
||||||
|
|
||||||
def pycapsule_new(self, ptr, name, clsname):
|
def pycapsule_new(self, ptr, name, clsname):
|
||||||
name_soften = mangle(name)
|
name_soften = mangle(name)
|
||||||
ret = self.call('pycapsule_new', 'PyObject*', ptr, quote(name),
|
cast_to_base = 'cast_to_base<%s >::from(%s)' % (name, ptr)
|
||||||
|
ret = self.call('pycapsule_new', 'PyObject*', cast_to_base, quote(name),
|
||||||
quote(clsname))
|
quote(clsname))
|
||||||
with self.block('if (!%(ret)s)' % locals()):
|
with self.block('if (!%(ret)s)' % locals()):
|
||||||
self.return_null()
|
self.return_null()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ extern "C" {
|
||||||
|
|
||||||
#if (PY_MAJOR_VERSION >= 3)
|
#if (PY_MAJOR_VERSION >= 3)
|
||||||
|
|
||||||
PyObject *
|
PyMODINIT_FUNC
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ template<class Td>
|
||||||
struct typecast {
|
struct typecast {
|
||||||
template<class Ts> static
|
template<class Ts> static
|
||||||
Td* from(Ts* src) {
|
Td* from(Ts* src) {
|
||||||
|
// check why this is only used in Python3
|
||||||
return llvm::dyn_cast<Td>(src);
|
return llvm::dyn_cast<Td>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,3 +266,24 @@ struct typecast {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Td, class Tbase>
|
||||||
|
struct unwrap_as {
|
||||||
|
static
|
||||||
|
Td* from(void* src) {
|
||||||
|
Tbase* base = static_cast<Tbase*>(src);
|
||||||
|
return static_cast<Td*>(base);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Td>
|
||||||
|
struct cast_to_base {
|
||||||
|
template<class Ts> static
|
||||||
|
Td* from(Ts* src){
|
||||||
|
return static_cast<Td*>(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Ts> static
|
||||||
|
const Td* from(const Ts* src){
|
||||||
|
return static_cast<const Td*>(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <llvm/ADT/SmallVector.h>
|
#include <llvm/ADT/SmallVector.h>
|
||||||
#include <llvm/Value.h>
|
#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3
|
||||||
#include <llvm/DerivedTypes.h>
|
#include <llvm/IR/Value.h>
|
||||||
#include <llvm/Function.h>
|
#include <llvm/IR/DerivedTypes.h>
|
||||||
|
#include <llvm/IR/Function.h>
|
||||||
|
#include <llvm/IR/Module.h>
|
||||||
|
#include <llvm/IR/Constants.h>
|
||||||
|
#include <llvm/IR/Intrinsics.h>
|
||||||
|
#include <llvm/IR/IRBuilder.h>
|
||||||
|
#if LLVM_VERSION_MINOR >= 4
|
||||||
|
#include <llvm/Support/MemoryObject.h>
|
||||||
|
#include <llvm/MC/MCDisassembler.h>
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <llvm/Value.h>
|
||||||
|
#include <llvm/DerivedTypes.h>
|
||||||
|
#include <llvm/Function.h>
|
||||||
|
#include <llvm/Module.h>
|
||||||
|
#include <llvm/Constants.h>
|
||||||
|
#include <llvm/Intrinsics.h>
|
||||||
|
#include <llvm/IRBuilder.h>
|
||||||
|
#endif
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
#include <llvm/Support/FormattedStream.h>
|
#include <llvm/Support/FormattedStream.h>
|
||||||
#include <llvm/Support/MemoryBuffer.h>
|
#include <llvm/Support/MemoryBuffer.h>
|
||||||
|
|
@ -12,14 +30,11 @@
|
||||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||||
#include <llvm/ExecutionEngine/GenericValue.h>
|
#include <llvm/ExecutionEngine/GenericValue.h>
|
||||||
#include <llvm/Linker.h>
|
#include <llvm/Linker.h>
|
||||||
#include <llvm/Module.h>
|
|
||||||
#include <llvm/Analysis/Verifier.h>
|
#include <llvm/Analysis/Verifier.h>
|
||||||
#include <llvm/Constants.h>
|
|
||||||
#include <llvm/Intrinsics.h>
|
|
||||||
#include <llvm/IRBuilder.h>
|
|
||||||
#include <llvm/PassRegistry.h>
|
#include <llvm/PassRegistry.h>
|
||||||
#include <llvm/Support/Host.h>
|
#include <llvm/Support/Host.h>
|
||||||
|
|
||||||
|
#include <llvm/ExecutionEngine/MCJIT.h> // to make MCJIT working
|
||||||
|
|
||||||
#include "auto_pyobject.h"
|
#include "auto_pyobject.h"
|
||||||
|
|
||||||
|
|
@ -56,6 +71,15 @@ namespace extra{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
PyObject* callwrite(PyObject* self, PyObject* arg)
|
||||||
|
{
|
||||||
|
char meth[] = "write";
|
||||||
|
char fmt[] = "O";
|
||||||
|
return PyObject_CallMethod(self, meth, fmt, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args)
|
PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args)
|
||||||
{
|
{
|
||||||
|
|
@ -162,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) {
|
||||||
PyObject* cap = pycapsule_new(&*begin, capsuleName, className);
|
auto_pyobject cap = pycapsule_new(&*begin, capsuleName, className);
|
||||||
PyList_Append(list, cap);
|
PyList_Append(list, *cap);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
@ -174,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) {
|
||||||
PyObject* cap = pycapsule_new(*begin, capsuleName, className);
|
auto_pyobject cap = pycapsule_new(*begin, capsuleName, className);
|
||||||
PyList_Append(list, cap);
|
PyList_Append(list, *cap);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +294,12 @@ llvm::ExecutionEngine* ExecutionEngine_create(
|
||||||
ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter,
|
ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter,
|
||||||
&ErrorStr, OptLevel,
|
&ErrorStr, OptLevel,
|
||||||
GVsWithCode);
|
GVsWithCode);
|
||||||
PyFile_WriteString(ErrorStr.c_str(), errout);
|
auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str());
|
||||||
|
if (errout && NULL == callwrite(errout, *buf)){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFile_WriteString(ErrorStr.c_str(), errout);
|
||||||
return ee;
|
return ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,7 +321,11 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT(
|
||||||
std::string ErrorStr;
|
std::string ErrorStr;
|
||||||
ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL,
|
ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL,
|
||||||
GCsWithCode, RM, CMM);
|
GCsWithCode, RM, CMM);
|
||||||
PyFile_WriteString(ErrorStr.c_str(), errout);
|
auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str());
|
||||||
|
if (errout && NULL == callwrite(errout, *buf)){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// PyFile_WriteString(ErrorStr.c_str(), errout);
|
||||||
return ee;
|
return ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,7 +507,7 @@ PyObject* llvm_ParseBitCodeFile(llvm::StringRef Buf, llvm::LLVMContext& Ctx,
|
||||||
std::string ErrStr;
|
std::string ErrStr;
|
||||||
M = ParseBitcodeFile(MB, Ctx, &ErrStr);
|
M = ParseBitcodeFile(MB, Ctx, &ErrStr);
|
||||||
auto_pyobject buf = PyBytes_FromString(ErrStr.c_str());
|
auto_pyobject buf = PyBytes_FromString(ErrStr.c_str());
|
||||||
if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){
|
if (NULL == callwrite(FObj, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
|
// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
|
||||||
|
|
@ -498,7 +531,7 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj)
|
||||||
rso.flush();
|
rso.flush();
|
||||||
StringRef ref = rso.str();
|
StringRef ref = rso.str();
|
||||||
auto_pyobject buf = PyBytes_FromStringAndSize(ref.data(), ref.size());
|
auto_pyobject buf = PyBytes_FromStringAndSize(ref.data(), ref.size());
|
||||||
return PyObject_CallMethod(FObj, "write", "O", *buf);
|
return callwrite(FObj, *buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|
@ -512,9 +545,13 @@ PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf,
|
||||||
if (FObj) {
|
if (FObj) {
|
||||||
std::string ErrStr;
|
std::string ErrStr;
|
||||||
Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr);
|
Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr);
|
||||||
if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
|
auto_pyobject buf = PyBytes_FromString(ErrStr.c_str());
|
||||||
|
if (NULL == callwrite(FObj, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
Triple = getBitcodeTargetTriple(MB, Ctx);
|
Triple = getBitcodeTargetTriple(MB, Ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -538,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();
|
||||||
PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size());
|
auto_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;
|
||||||
|
|
@ -581,11 +618,17 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker,
|
||||||
PyObject* ErrMsg)
|
PyObject* ErrMsg)
|
||||||
{
|
{
|
||||||
std::string errmsg;
|
std::string errmsg;
|
||||||
|
#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3
|
||||||
|
bool failed = Linker->linkInModule(Mod, &errmsg);
|
||||||
|
#else
|
||||||
bool failed = Linker->LinkInModule(Mod, &errmsg);
|
bool failed = Linker->LinkInModule(Mod, &errmsg);
|
||||||
|
#endif
|
||||||
if (! failed) {
|
if (! failed) {
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
} else {
|
} else {
|
||||||
if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
|
||||||
|
auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
|
||||||
|
if (NULL == callwrite(ErrMsg, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
|
|
@ -603,9 +646,13 @@ PyObject* Linker_LinkModules(llvm::Module* Dest,
|
||||||
if (! failed) {
|
if (! failed) {
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
} else {
|
} else {
|
||||||
if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
|
||||||
|
if (NULL == callwrite(ErrMsg, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -665,9 +712,14 @@ PyObject* llvm_verifyModule(const llvm::Module& Fn,
|
||||||
bool failed = llvm::verifyModule(Fn, Action, &errmsg);
|
bool failed = llvm::verifyModule(Fn, Action, &errmsg);
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
|
||||||
|
if (NULL == callwrite(ErrMsg, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
} else {
|
} else {
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
|
|
@ -790,9 +842,13 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename,
|
||||||
std::string errmsg;
|
std::string errmsg;
|
||||||
failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg);
|
failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg);
|
||||||
if (failed) {
|
if (failed) {
|
||||||
if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
|
||||||
|
if (NULL == callwrite(ErrMsg, *buf)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
failed = DynamicLibrary::LoadLibraryPermanently(Filename);
|
failed = DynamicLibrary::LoadLibraryPermanently(Filename);
|
||||||
|
|
@ -805,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{
|
class PassRegistryEnumerator : public llvm::PassRegistrationListener{
|
||||||
public:
|
public:
|
||||||
PyObject* List;
|
PyObject* List;
|
||||||
|
|
@ -814,7 +891,8 @@ 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());
|
||||||
PyList_Append(List, Py_BuildValue("(OO)", passArg, passName));
|
auto_pyobject pair = Py_BuildValue("(OO)", passArg, passName);
|
||||||
|
PyList_Append(List, *pair);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -835,7 +913,12 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Triple,
|
||||||
std::string error;
|
std::string error;
|
||||||
const Target* target = TargetRegistry::lookupTarget(Triple, error);
|
const Target* target = TargetRegistry::lookupTarget(Triple, error);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
PyFile_WriteString(error.c_str(), Error);
|
// PyFile_WriteString(error.c_str(), Error);
|
||||||
|
auto_pyobject buf = PyBytes_FromString(error.c_str());
|
||||||
|
if (NULL == callwrite(Error, *buf)){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
} else {
|
} else {
|
||||||
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
||||||
|
|
@ -852,14 +935,18 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Arch,
|
||||||
std::string error;
|
std::string error;
|
||||||
const Target* target = TargetRegistry::lookupTarget(Arch, Triple, error);
|
const Target* target = TargetRegistry::lookupTarget(Arch, Triple, error);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
PyFile_WriteString(error.c_str(), Error);
|
// PyFile_WriteString(error.c_str(), Error);
|
||||||
|
auto_pyobject buf = PyBytes_FromString(error.c_str());
|
||||||
|
if (NULL == callwrite(Error, *buf)){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
} else {
|
} else {
|
||||||
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error)
|
PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error)
|
||||||
{
|
{
|
||||||
|
|
@ -867,7 +954,12 @@ PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error)
|
||||||
std::string error;
|
std::string error;
|
||||||
const Target* target = TargetRegistry::getClosestTargetForJIT(error);
|
const Target* target = TargetRegistry::getClosestTargetForJIT(error);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
PyFile_WriteString(error.c_str(), Error);
|
auto_pyobject buf = PyBytes_FromString(error.c_str());
|
||||||
|
if (NULL == callwrite(Error, *buf)){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PyFile_WriteString(error.c_str(), Error);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
} else {
|
} else {
|
||||||
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
return pycapsule_new(const_cast<Target*>(target), "llvm::Target");
|
||||||
|
|
@ -875,6 +967,66 @@ PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
PyObject* TargetRegistry_targets_list()
|
||||||
|
{
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
return iterator_to_pylist_deref<TargetRegistry::iterator>(
|
||||||
|
TargetRegistry::begin(), TargetRegistry::end(),
|
||||||
|
"llvm::Target", "llvm::Target");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 4
|
||||||
|
static
|
||||||
|
PyObject* MemoryObject_readBytes(const llvm::MemoryObject *mobj,
|
||||||
|
uint64_t addr,
|
||||||
|
uint64_t size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
uint8_t *bytes;
|
||||||
|
PyObject* po;
|
||||||
|
|
||||||
|
if(size < 1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
bytes = new uint8_t[size];
|
||||||
|
if(bytes == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
status = mobj->readBytes(addr, size, bytes);
|
||||||
|
if(status != 0) {
|
||||||
|
delete bytes;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
po = PyBytes_FromStringAndSize((const char *) bytes, size);
|
||||||
|
delete bytes;
|
||||||
|
|
||||||
|
return po;
|
||||||
|
fail:
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
PyObject* MCDisassembler_getInstruction(llvm::MCDisassembler *disasm,
|
||||||
|
llvm::MCInst &instr,
|
||||||
|
const llvm::MemoryObject ®ion,
|
||||||
|
uint64_t address
|
||||||
|
)
|
||||||
|
{
|
||||||
|
uint64_t size;
|
||||||
|
llvm::MCDisassembler::DecodeStatus status;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
status = disasm->getInstruction(instr, size, region, address,
|
||||||
|
llvm::nulls(), llvm::nulls());
|
||||||
|
return Py_BuildValue("(i,i)", int(status), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* llvm >= 3.4 */
|
||||||
|
|
||||||
static
|
static
|
||||||
PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features)
|
PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features)
|
||||||
{
|
{
|
||||||
|
|
@ -898,3 +1050,23 @@ PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3
|
||||||
|
static
|
||||||
|
PyObject* llvm_sys_isLittleEndianHost()
|
||||||
|
{
|
||||||
|
if (llvm::sys::IsLittleEndianHost)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
else
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
PyObject* llvm_sys_isBigEndianHost()
|
||||||
|
{
|
||||||
|
if (llvm::sys::IsBigEndianHost)
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
else
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ components = ['core', 'analysis', 'scalaropts',
|
||||||
'interpreter', 'bitreader',
|
'interpreter', 'bitreader',
|
||||||
'bitwriter', 'instrumentation', 'ipa',
|
'bitwriter', 'instrumentation', 'ipa',
|
||||||
'ipo', 'transformutils', 'asmparser',
|
'ipo', 'transformutils', 'asmparser',
|
||||||
'linker', 'support', 'vectorize',
|
'linker', 'support', 'vectorize', 'all-targets'
|
||||||
]
|
]
|
||||||
|
|
||||||
nvptx = ['nvptx',
|
nvptx = ['nvptx',
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue