Compare commits

...
Sign in to create a new pull request.

153 commits

Author SHA1 Message Date
Siu Kwan Lam
34900d2748 Update README.rst 2014-04-29 13:25:43 -05:00
Siu Kwan Lam
749b518b90 Update changelog 2014-04-28 11:06:48 -05:00
Siu Kwan Lam
c07fce0477 Update MANIFEST.in (#99) 2014-04-28 11:03:13 -05:00
Siu Kwan Lam
7f8476dd33 Fixing leaks (#92); thanks to ksshelt and eltjpm. 2014-04-04 15:14:47 -05:00
Siu Kwan Lam
57afefb069 Update change log 2014-03-20 15:00:11 -05:00
Siu Kwan Lam
0629ccb226 Allow BasicBlock downcast to Value 2014-03-19 11:33:01 -05:00
Siu Kwan Lam
6e4620edc6 Disable check_intrinsic 2014-03-13 13:47:09 -05:00
Siu Kwan Lam
2410267c8e Disable isolated test in conda build 2014-03-13 13:20:08 -05:00
Siu Kwan Lam
bc12aae8c1 Hashable Module and fix Module __eq__ 2014-03-11 15:17:06 -05:00
Siu Kwan Lam
6578412437 Add binding for dynamic library loading 2014-03-06 11:58:40 -06:00
Siu Kwan Lam
ce696c9b4e Update changelog 2014-02-18 14:30:39 -06:00
Siu Kwan Lam
3befa1be59 Merge pull request #94 from cgohlke/patch-1
Fix ImportError for C extensions on Python 3.4b2
2014-02-18 14:27:32 -06:00
Siu Kwan Lam
a9174f09c5 Merge pull request #88 from cantora/tests-import-TestCase
Fix broken tests from test refactor
2014-02-18 14:20:39 -06:00
Siu Kwan Lam
b86cc097d9 Fix deprecated function use 2014-02-18 14:13:40 -06:00
Jay Bourque
0e9f434ad8 Fix release date year in CHANGELOG 2014-02-10 10:54:08 -06:00
cgohlke
e868b825bb Fix ImportError of C extensions on Python 3.4b2 2014-02-04 15:52:41 -08:00
Ilan Schnell
dd2a569d76 fix release date 2014-02-04 14:22:53 -06:00
Siu Kwan Lam
059192f1ae Update change log 2014-01-31 17:33:32 -06:00
Siu Kwan Lam
3db6d8352a Fix isolated test runner 2014-01-16 18:34:19 -06:00
Siu Kwan Lam
00db78d89e Edit conda buildscript 2014-01-16 17:45:15 -06:00
Siu Kwan Lam
d9eb3ec175 Update setup.py 2014-01-16 17:11:21 -06:00
Siu Kwan Lam
4ed8f80774 Fix avx_support; only run check_intrinsics for conda build test 2014-01-16 17:03:40 -06:00
Siu Kwan Lam
43095609c3 Add intrinsic check 2014-01-16 16:49:23 -06:00
Siu Kwan Lam
b9cccbf9ae Close everything properly 2014-01-16 11:22:52 -06:00
Siu Kwan Lam
8689d62f02 Fix for PY3 2014-01-15 17:41:15 -06:00
Siu Kwan Lam
17d3cef4bd Fix build_pass_manager fpm handling 2013-12-31 16:57:45 -06:00
Siu Kwan Lam
ecac668bef Fix inline threshold and add size level 2013-12-27 22:21:33 -06:00
Siu Kwan Lam
078f1fe5c1 Move capsule code into C++ 2013-12-23 17:17:12 -06:00
Siu Kwan Lam
b9752e1e98 Add deprecated module and deprecate alloca_array 2013-12-20 12:26:35 -06:00
Siu Kwan Lam
f8c1c78df1 Leaner 2013-12-18 15:25:14 -06:00
Siu Kwan Lam
b8e0338da8 Add AllocaInstruction 2013-12-18 10:43:11 -06:00
Siu Kwan Lam
091a393d1d insert_value, extract_value can be multiple dimensional 2013-12-16 14:05:19 -06:00
anthony cantor
d7590fb029 change module name from llvm.test_llvmpy to llvm.tests.support
this seems to have been forgotten when test stuff was refactored.
2013-12-03 02:37:47 -07:00
Troy Powell
c199881b67 fixing index.rst 2013-11-18 15:59:01 -06:00
Ilan Schnell
fb3b6a3674 update changelog 2013-11-11 15:22:39 -06:00
Siu Kwan Lam
4e814b7d53 skip test for building executable from native object and assembly on OSX 2013-11-11 12:20:43 -06:00
Siu Kwan Lam
8a6dd7af7f fix loop-vectorize for llvm-3.3 2013-11-05 16:58:20 -06:00
Siu Kwan Lam
d08095299e add example for using vector instructions 2013-11-01 16:58:49 -05:00
Siu Kwan Lam
bf5859be7e fix bad version checking which disables auto-vectorization for llvm 3.3 2013-11-01 16:50:53 -05:00
Siu Kwan Lam
18d3b4809f Fix py2.6--use Popen instead of check_output 2013-10-05 13:55:26 +08:00
Siu Kwan Lam
a82e876f93 Add test skipping to disable arch specific tests conditionally 2013-10-05 13:37:04 +08:00
Siu Kwan Lam
1f7b9e3922 Fix setup.py 2013-10-04 15:35:22 +08:00
Siu Kwan Lam
fac1bc782d Reorganize and cleanup tests 2013-10-04 15:24:30 +08:00
Siu Kwan Lam
ea452bd33c Fix test 2013-09-30 17:18:30 -05:00
Siu Kwan Lam
ddf2007553 Adjust test for win32 x86 ABI 2013-09-30 17:13:06 -05:00
Siu Kwan Lam
e7a7896710 Adjust test for win32 amd64 ABI 2013-09-30 16:59:46 -05:00
Siu Kwan Lam
69a78d0a54 Test ABI for structures and reorganize tests a bit. 2013-09-30 16:24:26 -05:00
Siu Kwan Lam
cc4e4631bd fix windows build: include all LLVM static library 2013-09-19 17:38:46 -05:00
Siu Kwan Lam
8034854ad4 make visual studio happy 2013-09-19 17:11:54 -05:00
Siu Kwan Lam
733fd7d18e fix missing re-export for old llvm.ee symbols 2013-09-19 15:05:29 -05:00
Siu Kwan Lam
6e55bfc406 fix spaces redundant trailing spaces and missing line break at EOF 2013-09-18 11:58:05 -05:00
anthony cantor
72192c7e6a fixed documentation typo 2013-09-18 11:52:22 -05:00
anthony cantor
b303fd532a fixes to make this branch compatible with llvm versions before 3.4 2013-09-18 11:52:22 -05:00
anthony cantor
aa264cee2d added align parameter to llvm.mc.Disassembler.decode
i cant find any method in llvm to automatically get the
correct instruction alignment for disassembling. i thought
it would be MCAsmInfo.getMinInstAlignment, but that value is
1 for the ARM target machine. since that is clearly the wrong
instruction alignment for disassembling arm, the user should
be able to configure the alignment to whatever is needed.
2013-09-18 11:52:22 -05:00
anthony cantor
3743146121 only convert input bytes if they are a string and we are in python 3
in python 2 'str' and 'bytes' are the same. if input bytes are not
a string or bytes, then raise a TypeError.
2013-09-18 11:52:22 -05:00
anthony cantor
8de5c3faff added some methods to llvm.mc.Operand
methods that describe what type of operand it is
2013-09-18 11:52:22 -05:00
anthony cantor
083586464b add bindings for instruction description methods to MCInstrDesc
use these new bindings instead of MCInstrAnalysis bindings in
llvm.mc.Instr because MCInstrAnalaysis is just a thin layer
encapsulating MCInstrInfo that seems largely pointless.
2013-09-18 11:52:22 -05:00
anthony cantor
0f3d5a8127 decode yields a tuple of integers instead of a bytearray
a tuple of integers is immutable and more similar to python 3
bytes than bytearray
2013-09-18 11:52:22 -05:00
anthony cantor
3e77a55de3 added methods to Instr which describe possible branch/terminator properties 2013-09-18 11:52:22 -05:00
anthony cantor
65c4558cac added opcode property to llvm.mc.Instr 2013-09-18 11:52:22 -05:00
anthony cantor
43f7330fda llvm.mc.Disassembler.decode now yields the byte sequence which generated the instruction
added custom method to extra.h to return a PyBytes object
from the bytes read from MemoryObject.readBytes.

also moved the generic methods from StringRefMemoryObject
up to MemoryObject
2013-09-18 11:52:22 -05:00
anthony cantor
1d735e49d2 fix python2/3 incompatibility
bytes built-in is different in python2
2013-09-18 11:52:22 -05:00
anthony cantor
fea82991c3 convert str input to bytes
StringRefMemoryObject constructor binding specifies bytes as
its input parameter, so we have to convert it.
2013-09-18 11:52:22 -05:00
anthony cantor
b3bf7f86cd MCExpr pointer is owned by the MCOperand object 2013-09-18 11:52:22 -05:00
anthony cantor
3c06f0d590 add flags, ts_flags properties for Instr class 2013-09-18 11:52:22 -05:00
anthony cantor
cadc53f174 no need for get method in TargetInstrInfo
MCInstrInfo parent already has a binding
2013-09-18 11:52:22 -05:00
anthony cantor
0ed471d336 added example-instruction-info.py
demonstrates getting flag information for an opcode
2013-09-18 11:52:22 -05:00
anthony cantor
7234b0d200 use getRegInfo instead of creating a register info object
also raise exception if a property is accessed which is not
available on that particular TargetMachine.
2013-09-18 11:52:22 -05:00
anthony cantor
fa3aec8353 added some bindings to TargetMachine methods
these methods return pointers to MC objects relevant
to the arch the TargetMachine represents.
2013-09-18 11:52:21 -05:00
anthony cantor
bd9d71c713 added some bindings for MC classes 2013-09-18 11:52:21 -05:00
anthony cantor
8dbfc377ad added functionality to llvm.mc.Instr to print itself
uses binding of printInst on MCInstPrinter for printing
instruction.

also fixed a bug in llvm.mc.Disassembler.decode: idx should
start at zero, and we should pass code.getBase() + idx to
getInstruction. idx must start at zero because the while loop
compares it against code.getExtent() which returns only the
length of bs.
2013-09-18 11:52:21 -05:00
anthony cantor
82d9c787f3 added llvm.mc.Operand class
Operand encapsulates information that llvm provides about an MCOperand
in an instruction.
2013-09-18 11:52:21 -05:00
anthony cantor
87d444c9e9 added tests to testall for llvm.target and llvm.mc
tests dont check for correctness, just exercise the API
2013-09-18 11:52:21 -05:00
anthony cantor
fa26aa1651 fix typo 2013-09-18 11:52:21 -05:00
anthony cantor
cbf4a61a17 moved the MC data type access to TargetMachine
Disassembler now simply needs a TargetMachine object
and it will be able to access all the descriptor objects
it needs for disassembly through the target machine.
2013-09-18 11:52:21 -05:00
anthony cantor
0e265a2cc5 TargetTransformInfo stuff doesnt work in llvm >= 3.3 2013-09-18 11:52:21 -05:00
anthony cantor
e65f6174a7 some fixes so that test/testall.py will run
some easy changes to core.py which were just conditionals on llvm
version. for the broken tests which i didnt know how to fix i
simply disabled them.
2013-09-18 11:52:21 -05:00
anthony cantor
83299a20a6 refactor TargetMachine into a new target module
TargetMachine is generally useful outside of the execution engine
context so i think it makes sense to move it into its own module.
2013-09-18 11:52:21 -05:00
anthony cantor
97c0e15e72 add some MCAsmInfo bindings 2013-09-18 11:52:21 -05:00
anthony cantor
4eab936224 added new MC classes for richer disassembling functionality 2013-09-18 11:52:21 -05:00
anthony cantor
78be6a7f5f conditionals for compatibility with llvm < 3.4
i only intend to support MC bindings (and anything reliant on MC)
for llvm 3.4 and greater.
2013-09-18 11:52:21 -05:00
anthony cantor
bc02b3d90a use (llvm 3.4) built in StringRefMemoryObject instead of BytesMemoryObject 2013-09-18 11:52:21 -05:00
anthony cantor
aa0ee9b6a6 changes to make llvmpy compatible with development branch of llvm
mostly just removing stuff and changing function prototypes.
with these changes, llvmpy compiles and llvm.test() passes.
2013-09-18 11:52:21 -05:00
anthony cantor
0610a27535 add MCAsmInfo 2013-09-18 11:52:21 -05:00
anthony cantor
f4bbb18e47 fixed arm test: arm code needs to be reverse b.c. its little endian 2013-09-18 11:52:20 -05:00
anthony cantor
25e6651055 added MCOperand methods 2013-09-18 11:52:20 -05:00
anthony cantor
38a00c6e55 fixed typo in new_from_triple and added args to new_from_name
new_from_triple: need to pass subtarget info to new_from_target

new_from_name: allow caller to pass cpu and feature info
2013-09-18 11:52:20 -05:00
anthony cantor
818c9289fc implemented binding for MCDisassembler.getInstruction
also added new llvm.mc module to act as higher level
python access to the MC section of LLVM (added Instr
and Disassembler classes).
2013-09-18 11:52:20 -05:00
anthony cantor
ba03b226c8 added Target.createMCSubtargetInfo and createMCDisassembler
also added bindings to classes required by the target methods. also
added a convenience function to initialize all target components to
the llvm module
2013-09-18 11:52:20 -05:00
anthony cantor
8f2c27ba41 added TargetRegistry_targets_list
this allows all targets to be enumerated. this is generally useful,
but i specifically wanted to be able to see which targets report
having a disassembler. it is necessary to init the various
target components in order for them to report that they have one,
thus i added InitializeAllDisassemblers and InitializeAllAsmParsers
to TargetSelect.py
2013-09-18 11:52:20 -05:00
anthony cantor
ef59848d18 modify build process to support all targets
my goal is to facillitate a wide range of disassembly capability through
llvm disassemblers, so supporting as many machine targets as possible is ideal.
2013-09-18 11:52:20 -05:00
anthony cantor
4905743e0a add BytesMemoryObject to extra.h and a binding for it in llvmpy/src 2013-09-18 11:52:20 -05:00
Jon Riehl
09d9dbba1e Merge pull request #83 from sergiopasra/noshebang
Remove shebangs from library code
2013-09-09 14:12:40 -07:00
Sergio Pascual
aae25f5e55 Remove shebangs from library code 2013-09-09 13:00:01 +02:00
Siu Kwan Lam
af2c1d6d01 update change log 2013-08-28 17:11:03 -05:00
Siu Kwan Lam
4e993570cd disable logging to avoid a exception ignored message 2013-08-28 14:18:35 -05:00
Siu Kwan Lam
6bbf53241d revive a casting code in the binding 2013-08-28 13:55:38 -05:00
Siu Kwan Lam
0801df41dc fix upcasting problem (#77 thanks to cantora) 2013-08-26 12:23:28 -05:00
Siu Kwan Lam
24f1b33737 Fix a ownership bug (thanks to cantora) 2013-08-23 10:59:47 -05:00
Siu Kwan Lam
536bc37c94 Disable MCJIT test on windows 64-bit (#79) 2013-08-22 14:13:17 -05:00
Jay Bourque
351bd39814 Python3 fix: Implement __hash__ method for Value class 2013-08-20 17:20:57 -05:00
majidaldo
33ca795e0c remove chrpath 2013-08-16 11:50:38 -05:00
Siu Kwan Lam
d57c4d88c6 fix x86 arch type for LLRT 2013-08-14 18:25:32 -05:00
Siu Kwan Lam
328f88bbd5 llvm3.3 has a different TargetTransformInfo 2013-08-14 18:18:05 -05:00
Siu Kwan Lam
ea5b430297 add IR files in setup.py 2013-08-14 18:09:17 -05:00
Siu Kwan Lam
5f01343bba Merge branch 'llrt' 2013-08-14 17:45:58 -05:00
Siu Kwan Lam
bf8693bb80 disable float div/mod test temporarily 2013-08-14 17:45:38 -05:00
Siu Kwan Lam
e69048ad3d add div64 and mod64 2013-08-14 17:24:34 -05:00
Siu Kwan Lam
8480d55faf add sdivmod;
improve build system;
2013-08-14 15:29:13 -05:00
majidaldo
7d1c4c18a0 high version number 2013-08-14 14:39:10 -05:00
Siu Kwan Lam
07c64779d8 begin low-level runtime implementation 2013-08-13 18:38:41 -05:00
Siu Kwan Lam
d10b182479 dislabe MCJIT tests for LLVM3.2 2013-08-13 15:27:54 -05:00
majidaldo
1be8b07ced charpath just for linux 2013-08-13 14:59:33 -05:00
majidaldo
3a289ccace add percent python 2013-08-13 14:55:42 -05:00
majidaldo
bf0253c9f9 add chrpath 2013-08-13 14:55:13 -05:00
majidaldo
d060c10096 add conda build script 2013-08-13 14:42:54 -05:00
Siu Kwan Lam
1ed3c77310 add neg nuw nsw 2013-08-12 16:16:38 -05:00
Siu Kwan Lam
cfe5e9ea92 add exact flag to IRBuilder 2013-08-12 16:11:34 -05:00
Siu Kwan Lam
1e9d37a64e add no-signed-wrap and no-unsigned-wrap flags to IRBuilder 2013-08-12 15:59:17 -05:00
Siu Kwan Lam
eb4fc653f2 ensure MCJIT ELF autoselect works 2013-08-12 14:52:16 -05:00
Siu Kwan Lam
b4d943a671 add autoselect ELF generation for MCJIT 2013-08-12 14:43:30 -05:00
Siu Kwan Lam
c20c4d776f fix exception handling for TargetMachine 2013-08-12 14:43:30 -05:00
Ilan Schnell
84a95945ea update marker header file 2013-08-06 14:17:14 -05:00
Siu Kwan Lam
0421ad8456 add dev docs 2013-08-02 12:12:47 -05:00
Siu Kwan Lam
2a25b1c2b3 fix avx detection for py3 2013-08-01 13:04:04 -05:00
Siu Kwan Lam
c4db61c7f5 add test for basic arith operators and problems for div and mod on 32bit platforms 2013-08-01 13:02:45 -05:00
Siu Kwan Lam
c0e9dedc90 add binding to dynamiclibrary namespace for multimodule linking 2013-07-31 17:50:30 -05:00
Siu Kwan Lam
319984f0e0 add MCJIT test 2013-07-31 16:57:29 -05:00
Siu Kwan Lam
56a511854a update "attribute(s)" ignorance 2013-07-31 16:43:50 -05:00
Siu Kwan Lam
625858aa6f fixes 2013-07-31 16:05:24 -05:00
Siu Kwan Lam
6d3253e4ea Add things to make MCJIT working 2013-07-31 15:44:01 -05:00
Siu Kwan Lam
4c1b9016fb binding compiles with llvm 3.3 2013-07-31 15:12:23 -05:00
Siu Kwan Lam
2338eae5f6 Fix py3 str has no buffer interface 2013-06-13 17:17:43 -05:00
Siu Kwan Lam
2415042a2a DIDescriptor does not inherit MDNode 2013-05-31 15:01:02 -05:00
Siu Kwan Lam
ad287faeb1 Fixes a werid case of refct problem 2013-05-31 14:01:57 -05:00
Ilan Schnell
69c75355f4 fix future import 2013-05-31 11:47:51 -05:00
Siu Kwan Lam
84f1b433de Use if-else instead of try-except for perf reason 2013-05-30 14:04:08 -05:00
Siu Kwan Lam
2e8944916c Add DIBuilder binding 2013-05-29 19:13:45 -05:00
Siu Kwan Lam
17ec89e457 Fix win32 build 2013-05-28 19:23:45 -05:00
Mark Florisson
6b333e84aa Use error message string from BytesIO 2013-05-27 12:22:13 +01:00
Travis E. Oliphant
009239713e Update llvm_array concepts. 2013-05-25 13:35:45 -05:00
Travis E. Oliphant
1812cff2d0 Fix import problem. 2013-05-25 13:34:14 -05:00
Siu Kwan Lam
a0eb03b239 Fix CompareInstruction.predicate 2013-05-23 11:45:15 -05:00
Siu Kwan Lam
5b2b878f24 Enable MCJIT 2013-05-22 15:17:59 -05:00
Siu Kwan Lam
edab81ed7e Fix GC problem with Module when it is GCed but re-instantiate from GlobalValue.module. 2013-05-17 14:05:40 -05:00
Siu Kwan Lam
96dc907613 Make enum integer constants prints name 2013-05-16 13:46:57 -05:00
Siu Kwan Lam
592f9c6988 Allow retrieving argument attributes 2013-05-16 13:45:59 -05:00
Siu Kwan Lam
331f71f26f Fix hashing of llvm type 2013-05-16 11:34:27 -05:00
Siu Kwan Lam
db7323771f Fix PR 2013-05-14 11:23:50 -05:00
Travis E. Oliphant
f4b320ff09 Fix a few erros. Add an array type 2013-05-14 11:12:51 -05:00
Siu Kwan Lam
08bed7dd74 Fix bug with Module.to_bitcode() (Reported by Jun Koi) 2013-05-14 10:33:49 -05:00
Travis E. Oliphant
c118427118 Don't get name field from literal structure and avoid a segfault. 2013-05-14 04:26:10 -05:00
Siu Kwan Lam
3e0dc25070 Silent capsule memory logger. 2013-05-10 10:58:51 -05:00
144 changed files with 8730 additions and 2122 deletions

View file

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

View file

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

View file

@ -30,10 +30,13 @@ 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::

View file

@ -0,0 +1,6 @@
set LLVMPY_DYNLINK=0
set INCLUDE=%LIBRARY_INC%
set LIBPATH=%LIBRARY_LIB%
set LIB=%LIBRARY_LIB%
%PYTHON% setup.py install
if errorlevel 1 exit 1

View file

@ -0,0 +1,13 @@
#!/bin/bash
if [[ (`uname` == Linux) && (`uname -m` != armv6l) ]]
then
export CC=gcc
#gcc44
export CXX=g++
#g++44
fi
export LLVMPY_DYNLINK=$DISTRO_BUILD
$PYTHON setup.py install

View file

@ -0,0 +1,28 @@
package:
name: llvmpy
version: 99.9.9
source:
git_url: git@github.com:llvmpy/llvmpy.git
# git_tag: 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

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

View file

@ -3,8 +3,8 @@
You can adapt this file completely to your liking, but it should at least You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive. contain the root `toctree` directive.
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
View file

@ -0,0 +1,152 @@
'''
This example shows:
1) how to use vector instructions
2) how to take advantage of LLVM loop vectorization to transform scalar
operations to vector operations
'''
from __future__ import print_function
import llvm.core as lc
import llvm.ee as le
import llvm.passes as lp
from ctypes import CFUNCTYPE, POINTER, c_int, c_float
def build_manual_vector():
mod = lc.Module.new('manual.vector')
intty = lc.Type.int(32)
vecty = lc.Type.vector(lc.Type.float(), 4)
aryty = lc.Type.pointer(lc.Type.float())
fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty])
fn = mod.add_function(fnty, name='vector_add')
bbentry = fn.append_basic_block('entry')
bbloopcond = fn.append_basic_block('loop.cond')
bbloopbody = fn.append_basic_block('loop.body')
bbexit = fn.append_basic_block('exit')
builder = lc.Builder.new(bbentry)
# populate function body
in1, in2, out, size = fn.args
ZERO = lc.Constant.null(intty)
loopi_ptr = builder.alloca(intty)
builder.store(ZERO, loopi_ptr)
builder.branch(bbloopcond)
builder.position_at_end(bbloopcond)
loopi = builder.load(loopi_ptr)
loopcond = builder.icmp(lc.ICMP_ULT, loopi, size)
builder.cbranch(loopcond, bbloopbody, bbexit)
builder.position_at_end(bbloopbody)
vecaryty = lc.Type.pointer(vecty)
in1asvec = builder.bitcast(builder.gep(in1, [loopi]), vecaryty)
in2asvec = builder.bitcast(builder.gep(in2, [loopi]), vecaryty)
outasvec = builder.bitcast(builder.gep(out, [loopi]), vecaryty)
vec1 = builder.load(in1asvec)
vec2 = builder.load(in2asvec)
vecout = builder.fadd(vec1, vec2)
builder.store(vecout, outasvec)
next = builder.add(loopi, lc.Constant.int(intty, 4))
builder.store(next, loopi_ptr)
builder.branch(bbloopcond)
builder.position_at_end(bbexit)
builder.ret_void()
return mod, fn
def build_auto_vector():
mod = lc.Module.new('auto.vector')
# Loop vectorize is sensitive to the size of the index size(!?)
intty = lc.Type.int(tuple.__itemsize__ * 8)
aryty = lc.Type.pointer(lc.Type.float())
fnty = lc.Type.function(lc.Type.void(), [aryty, aryty, aryty, intty])
fn = mod.add_function(fnty, name='vector_add')
bbentry = fn.append_basic_block('entry')
bbloopcond = fn.append_basic_block('loop.cond')
bbloopbody = fn.append_basic_block('loop.body')
bbexit = fn.append_basic_block('exit')
builder = lc.Builder.new(bbentry)
# populate function body
in1, in2, out, size = fn.args
in1.add_attribute(lc.ATTR_NO_ALIAS)
in2.add_attribute(lc.ATTR_NO_ALIAS)
out.add_attribute(lc.ATTR_NO_ALIAS)
ZERO = lc.Constant.null(intty)
loopi_ptr = builder.alloca(intty)
builder.store(ZERO, loopi_ptr)
builder.branch(bbloopcond)
builder.position_at_end(bbloopcond)
loopi = builder.load(loopi_ptr)
loopcond = builder.icmp(lc.ICMP_ULT, loopi, size)
builder.cbranch(loopcond, bbloopbody, bbexit)
builder.position_at_end(bbloopbody)
in1elem = builder.load(builder.gep(in1, [loopi]))
in2elem = builder.load(builder.gep(in2, [loopi]))
outelem = builder.fadd(in1elem, in2elem)
builder.store(outelem, builder.gep(out, [loopi]))
next = builder.add(loopi, lc.Constant.int(intty, 1))
builder.store(next, loopi_ptr)
builder.branch(bbloopcond)
builder.position_at_end(bbexit)
builder.ret_void()
return mod, fn
def example(title, module_builder, opt):
print(title.center(80, '='))
mod, fn = module_builder()
eb = le.EngineBuilder.new(mod).opt(3)
if opt:
print('opt')
tm = eb.select_target()
pms = lp.build_pass_managers(mod=mod, tm=tm, opt=3, loop_vectorize=True,
fpm=False)
pms.pm.run(mod)
print(mod)
print(mod.to_native_assembly())
engine = eb.create()
ptr = engine.get_pointer_to_function(fn)
callable = CFUNCTYPE(None, POINTER(c_float), POINTER(c_float),
POINTER(c_float), c_int)(ptr)
N = 20
in1 = (c_float * N)(*range(N))
in2 = (c_float * N)(*range(N))
out = (c_float * N)()
print('in1: ', list(in1))
print('in1: ', list(in2))
callable(in1, in2, out, N)
print('out', list(out))
def main():
example('manual vector function', build_manual_vector, False)
example('auto vector function', build_auto_vector, True)
if __name__ == '__main__':
main()

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import opcode import opcode

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import dis import dis

View file

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

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import itertools import itertools

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
import ctypes import ctypes

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
import pprint import pprint

View file

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

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import sys import sys

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
import dis import dis

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin from .bytecode_visitor import BytecodeFlowVisitor, BenignBytecodeVisitorMixin

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
import ctypes import ctypes

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
def doslice (in_string, lower, upper): def doslice (in_string, lower, upper):

View file

@ -1,4 +1,3 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
import llvm.core as lc import llvm.core as lc

22
llrtc/Makefile Normal file
View 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
View 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
View file

@ -0,0 +1,4 @@
*.o
*.run
*.out
*.ll

66
llrtc/lib/Makefile Normal file
View 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
View 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
View 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
View 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
View 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;
}

View 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;
}

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

View 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;
}

View 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
View 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;
}

View 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)

View file

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

View file

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

File diff suppressed because it is too large Load diff

25
llvm/deprecated.py Normal file
View file

@ -0,0 +1,25 @@
"""
Shameless borrowed from Smart_deprecation_warnings
https://wiki.python.org/moin/PythonDecoratorLibrary
"""
import warnings
import functools
def deprecated(func):
"""This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used."""
@functools.wraps(func)
def new_func(*args, **kwargs):
warnings.warn_explicit(
"Call to deprecated function %s." % (func.__name__,),
category=DeprecationWarning,
filename=func.func_code.co_filename,
lineno=func.func_code.co_firstlineno + 1
)
return func(*args, **kwargs)
return new_func

View file

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

View file

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

File diff suppressed because it is too large Load diff

72
llvm/tests/__init__.py Normal file
View 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
View 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
View file

@ -0,0 +1,24 @@
import unittest
from llvm.core import Type, Module, Builder, Constant
from .support import TestCase, tests
class TestAlloca(TestCase):
def test_alloca_alignment(self):
m = Module.new('')
f = m.add_function(Type.function(Type.void(), []), "foo")
b = Builder.new(f.append_basic_block(''))
inst = b.alloca(Type.int(32))
inst.alignment = 4
b.ret_void()
m.verify()
self.assertTrue(inst.is_static)
self.assertFalse(inst.is_array)
self.assertEqual(inst.alignment, 4)
self.assertEqual(str(inst.array_size), 'i32 1')
tests.append(TestAlloca)
if __name__ == '__main__':
unittest.main()

View file

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

View 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
View file

View file

@ -0,0 +1,181 @@
from __future__ import print_function, absolute_import
import sys
from llvm.core import Type, Function, Builder, Module
import llvm.core as lc
import llvm.ee as le
import multiprocessing
from ctypes import *
INTRINSICS = {}
CTYPES_MAP = {
Type.int(): c_int32,
Type.int(64): c_int64,
Type.float(): c_float,
Type.double(): c_double,
}
def register(name, retty, *args):
def wrap(fn):
INTRINSICS[name] = (retty, args), fn
return fn
return wrap
def intr_impl(intrcode, *types):
def impl(module, builder, args):
intr = Function.intrinsic(module, intrcode, types)
r = builder.call(intr, args)
return r
return impl
register("llvm.powi.f64", Type.double(), Type.double(), Type.int())\
(intr_impl(lc.INTR_POWI, Type.double()))
register("llvm.powi.f32", Type.float(), Type.float(), Type.int())\
(intr_impl(lc.INTR_POWI, Type.float()))
register("llvm.pow.f64", Type.double(), Type.double(), Type.double())\
(intr_impl(lc.INTR_POW, Type.double()))
register("llvm.pow.f32", Type.float(), Type.float(), Type.float())\
(intr_impl(lc.INTR_POW, Type.float()))
register("llvm.sin.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_SIN, Type.double()))
register("llvm.sin.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_SIN, Type.float()))
register("llvm.cos.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_COS, Type.double()))
register("llvm.cos.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_COS, Type.float()))
register("llvm.log.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_LOG, Type.double()))
register("llvm.log.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_LOG, Type.float()))
register("llvm.log2.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_LOG2, Type.double()))
register("llvm.log2.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_LOG2, Type.float()))
register("llvm.log10.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_LOG10, Type.double()))
register("llvm.log10.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_LOG10, Type.float()))
register("llvm.sqrt.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_SQRT, Type.double()))
register("llvm.sqrt.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_SQRT, Type.float()))
register("llvm.exp.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_EXP, Type.double()))
register("llvm.exp.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_EXP, Type.float()))
register("llvm.exp2.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_EXP2, Type.double()))
register("llvm.exp2.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_EXP2, Type.float()))
register("llvm.fabs.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_FABS, Type.double()))
register("llvm.fabs.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_FABS, Type.float()))
register("llvm.floor.f64", Type.double(), Type.double())\
(intr_impl(lc.INTR_FLOOR, Type.double()))
register("llvm.floor.f32", Type.float(), Type.float())\
(intr_impl(lc.INTR_FLOOR, Type.float()))
def build_test(name):
(retty, args), impl = INTRINSICS[name]
module = Module.new("test.%s" % name)
fn = module.add_function(Type.function(retty, args), name="test_%s" % name)
builder = Builder.new(fn.append_basic_block(""))
retval = impl(module, builder, fn.args)
builder.ret(retval)
fn.verify()
module.verify()
return module, fn
def run_test(name):
module, fn = build_test(name)
eb = le.EngineBuilder.new(module).mcjit(True)
engine = eb.create()
ptr = engine.get_pointer_to_function(fn)
argtys = fn.type.pointee.args
retty = fn.type.pointee.return_type
cargtys = [CTYPES_MAP[a] for a in argtys]
cretty = CTYPES_MAP[retty]
cfunc = CFUNCTYPE(cretty, *cargtys)(ptr)
args = [1] * len(cargtys)
cfunc(*args)
def spawner(name):
print("Testing %s" % name)
proc = multiprocessing.Process(target=run_test, args=(name,))
print('-' * 80)
proc.start()
proc.join()
if proc.exitcode != 0:
print("FAILED")
ok = False
else:
print("PASSED")
ok = True
print('=' * 80)
print()
return ok
USAGE = """
Args: [name]
name: intrinsic name to test
If no name is given, test all intrinsics.
"""
def main(argv=()):
if len(argv) == 1:
intrname = argv[1]
spawner(intrname)
elif not argv:
failed = []
for name in sorted(INTRINSICS):
if not spawner(name):
failed.append(name)
print("Summary:")
for name in failed:
print("%s failed" % name)
else:
print(USAGE)
if __name__ == '__main__':
main(argv=sys.argv[1:])

View file

@ -12,7 +12,11 @@ http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf
""" """
import sys, os, subprocess import sys
import os
import subprocess
import contextlib
def detect_avx_support(option='detect'): 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
View file

@ -0,0 +1,2 @@
from __future__ import absolute_import
from .array import *

257
llvm_array/array.py Normal file
View 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()

View file

@ -349,7 +349,7 @@ class CBuilder(object):
elif not isinstance(count, lc.Value): elif not isinstance(count, lc.Value):
count = self.constant(types.int, count).value count = self.constant(types.int, count).value
ptr = self.builder.alloca_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):

View file

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

View file

@ -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 (module) {
CapsuleType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CapsuleType) < 0) {
INITERROR;
}
Py_INCREF(&CapsuleType);
PyModule_AddObject(module, "Capsule", (PyObject*)(&CapsuleType));
ConstantOne = PyInt_FromLong(1);
}
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
return module; return module;
#endif #endif
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}
};

View file

@ -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,20 +30,17 @@
#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"
namespace extra{ namespace extra{
using namespace llvm; using namespace llvm;
class raw_svector_ostream_helper: public raw_svector_ostream { class raw_svector_ostream_helper: public raw_svector_ostream {
SmallVectorImpl<char> *SV; SmallVectorImpl<char> *SV;
public: public:
@ -56,12 +71,21 @@ 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)
{ {
using extra::raw_svector_ostream_helper; using extra::raw_svector_ostream_helper;
using llvm::raw_svector_ostream; using llvm::raw_svector_ostream;
if (!PyArg_ParseTuple(args, "")) { if (!PyArg_ParseTuple(args, "")) {
return NULL; return NULL;
} }
@ -75,7 +99,7 @@ PyObject* make_small_vector_from_types(PyObject* self, PyObject* args)
{ {
using llvm::Type; using llvm::Type;
typedef llvm::SmallVector<llvm::Type*, 8> SmallVector_Type; typedef llvm::SmallVector<llvm::Type*, 8> SmallVector_Type;
SmallVector_Type* SV = new SmallVector_Type; SmallVector_Type* SV = new SmallVector_Type;
Py_ssize_t size = PyTuple_Size(args); Py_ssize_t size = PyTuple_Size(args);
for (Py_ssize_t i = 0; i < size; ++i) { for (Py_ssize_t i = 0; i < size; ++i) {
@ -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;
} }
@ -387,7 +420,7 @@ PyObject* ExecutionEngine_RunFunction(llvm::ExecutionEngine* EE,
PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?"); PyErr_SetString(PyExc_RuntimeError, "Failed to index into args?");
return NULL; return NULL;
} }
GenericValue* gv = static_cast<GenericValue*>( GenericValue* gv = static_cast<GenericValue*>(
PyCapsule_GetPointer(obj, GVN)); PyCapsule_GetPointer(obj, GVN));
@ -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 &region,
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

View file

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