Compare commits

..

2 commits

Author SHA1 Message Date
Siu Kwan Lam
ca192850ee Silent capsule memory logger. 2013-05-14 00:55:09 -05:00
Travis E. Oliphant
7a77be01cc Fix a few erros. Add an array type 2013-05-14 00:51:45 -05:00
143 changed files with 2204 additions and 8637 deletions

View file

@ -1,40 +1,3 @@
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,6 +1,5 @@
include CHANGELOG LICENSE README.rst setup.py MANIFEST.in versioneer.py include CHANGELOG LICENSE README setup.py MANIFEST.in
recursive-include llvm * recursive-include llvm *
recursive-include llvmpy *
recursive-include www * recursive-include www *
recursive-include test * recursive-include test *
recursive-include tools * recursive-include tools *

View file

@ -30,14 +30,11 @@ Quickstart
to separate your custom build from the default system package. Please to separate your custom build from the default system package. Please
replace ``LLVM_INSTALL_PATH`` with your own path. replace ``LLVM_INSTALL_PATH`` with your own path.
3. Run ``REQUIRES_RTTI=1 make install`` to build and install. 3. Run ``REQUIRES_RTTI=1 make`` to build.
**Note**: With LLVM 3.2, the default build configuration has C++ RTTI **Note**: With LLVM 3.2, the default build configuration has C++ RTTI
disabled. However, llvmpy requires RTTI. disabled. However, llvmpy requires RTTI.
**Note**: Use ``make -j2 install`` to enable concurrent build.
Replace ``2`` with the actual number of processor you have.
4. Get llvm-py and install it:: 4. Get llvm-py and install it::
$ git clone git@github.com:llvmpy/llvmpy.git $ git clone git@github.com:llvmpy/llvmpy.git

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
#! /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,3 +1,4 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import itertools import itertools

View file

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

View file

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

View file

@ -1,3 +1,4 @@
#! /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,3 +1,4 @@
#! /usr/bin/env python
# ______________________________________________________________________ # ______________________________________________________________________
from __future__ import absolute_import from __future__ import absolute_import
import sys import sys

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,11 +0,0 @@
#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);
}

View file

@ -1,19 +0,0 @@
#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_ */

View file

@ -1,15 +0,0 @@
#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;
}

View file

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

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

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

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

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

View file

@ -1,84 +0,0 @@
/*
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

@ -1,15 +0,0 @@
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,7 +2,6 @@ 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
@ -40,17 +39,55 @@ 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)
bpath = join(find_llvm_prefix(), 'lib') if isfile(join(find_llvm_prefix(), 'lib', 'LLVMPTXCodeGen.lib')):
for filename in listdir(bpath): print('-lLLVMPTXAsmPrinter')
filepath = join(bpath, filename) print('-lLLVMPTXCodeGen')
if isfile(filepath) and filename.endswith('.lib') and filename.startswith('LLVM'): print('-lLLVMPTXDesc')
name = filename.split('.', 1)[0] print('-lLLVMPTXInfo')
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:
@ -61,15 +98,12 @@ 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' , 'Linker.h')) ensure_file(join(incdir, 'llvm' , 'BasicBlock.h'))
print(incdir) print(incdir)
elif option == '--libdir': elif option == '--libdir':

View file

@ -4,13 +4,10 @@ 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
@ -34,14 +31,14 @@ def _extract_ptrs(objs):
class LLVMException(Exception): class LLVMException(Exception):
pass pass
def test(verbosity=3, run_isolated=True): def test(verbosity=1):
"""test(verbosity=1) -> TextTestResult """test(verbosity=1) -> TextTestResult
Run self-test, and return the number of failures + errors Run self-test, and return the number of failures + errors
""" """
from llvm.tests import run from llvm.test_llvmpy import run
result = run(verbosity=verbosity, run_isolated=run_isolated) result = run(verbosity=verbosity)
errct = len(result.failures) + len(result.errors)
return len(result.failures) + len(result.errors)
return errct

File diff suppressed because it is too large Load diff

View file

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

View file

@ -30,23 +30,33 @@
"Execution Engine and related classes." "Execution Engine and related classes."
import sys from io import BytesIO
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
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
# import items which were moved to target module # Enumerations
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
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
@ -140,17 +150,9 @@ 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()
ee = ExecutionEngine(engine) return 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
@ -165,12 +167,6 @@ 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
@ -192,9 +188,6 @@ 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)
@ -220,45 +213,151 @@ 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)
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
# Dynamic Library # Target machine
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
def dylib_add_symbol(name, ptr): def initialize_target(target, noraise=False):
api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr) """Initialize target by name.
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
""" """
return DynamicLibrary(filename) prefix = 'LLVMInitialize'
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
class DynamicLibrary(object): def print_registered_targets():
def __init__(self, filename): '''
""" Note: print directly to stdout
Raises RuntimeError '''
""" api.llvm.TargetRegistry.printRegisteredTargetsForVersion()
self._ptr = api.llvm.sys.DynamicLibrary.getPermanentLibrary(
filename) 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)
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)

View file

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

View file

@ -1,371 +0,0 @@
; 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
}

View file

@ -1,371 +0,0 @@
; 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
}

View file

@ -1,242 +0,0 @@
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,26 +70,6 @@ class PassManagerBuilder(llvm.Wrapper):
def size_level(self, sizelevel): def size_level(self, sizelevel):
self._ptr.SizeLevel = sizelevel self._ptr.SizeLevel = sizelevel
if llvm.version >= (3, 3):
@property
def bbvectorize(self):
return self._ptr.BBVectorize
@bbvectorize.setter
def bbvectorize(self, 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 @property
def vectorize(self): def vectorize(self):
return self._ptr.Vectorize return self._ptr.Vectorize
@ -129,7 +109,6 @@ class PassManagerBuilder(llvm.Wrapper):
def disable_unroll_loops(self, disable): def disable_unroll_loops(self, disable):
self._ptr.DisableUnrollLoops = disable self._ptr.DisableUnrollLoops = disable
if llvm.version <= (3, 3):
@property @property
def disable_simplify_lib_calls(self): def disable_simplify_lib_calls(self):
return self._ptr.DisableSimplifyLibCalls return self._ptr.DisableSimplifyLibCalls
@ -320,15 +299,13 @@ class TargetTransformInfo(Pass):
# Helpers # Helpers
#===----------------------------------------------------------------------=== #===----------------------------------------------------------------------===
def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False, def build_pass_managers(tm, opt=2, loop_vectorize=False, vectorize=False,
slp_vectorize=False, vectorize=False, inline_threshold=2000, pm=True, fpm=True, mod=None):
inline_threshold=None, pm=True, fpm=True, mod=None):
''' '''
tm --- The TargetMachine for which the passes are optimizing for. tm --- The TargetMachine for which the passes are optimizing for.
The TargetMachine must stay alive until the pass managers The TargetMachine must stay alive until the pass managers
are removed. are removed.
opt --- [0-3] Optimization level. Default to 2. opt --- [0-3] Optimization level. Default to 2.
size --- [0-2] Optimize for size. Default to 0.
loop_vectorize --- [boolean] Whether to use loop-vectorizer. loop_vectorize --- [boolean] Whether to use loop-vectorizer.
vectorize --- [boolean] Whether to use basic-block vectorizer. vectorize --- [boolean] Whether to use basic-block vectorizer.
inline_threshold --- [int] Threshold for the inliner. inline_threshold --- [int] Threshold for the inliner.
@ -337,18 +314,6 @@ def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False,
fpm --- [boolean] Whether to build a function-level pass-manager. fpm --- [boolean] Whether to build a function-level pass-manager.
mod --- [Module] The module object for the FunctionPassManager. mod --- [Module] The module object for the FunctionPassManager.
''' '''
if inline_threshold is None:
if 0 < opt < 3:
inline_threshold = 225
if size == 1:
inline_threshold = 75
elif size == 2:
inline_threshold = 25
if opt >= 3:
inline_threshold = 275
if pm: if pm:
pm = PassManager.new() pm = PassManager.new()
if fpm: if fpm:
@ -361,27 +326,22 @@ def build_pass_managers(tm, opt=2, size=0, loop_vectorize=False,
pmb.opt_level = opt pmb.opt_level = opt
pmb.vectorize = vectorize pmb.vectorize = vectorize
pmb.loop_vectorize = loop_vectorize pmb.loop_vectorize = loop_vectorize
if llvm.version >= (3, 3):
pmb.slp_vectorize = slp_vectorize
if inline_threshold: if inline_threshold:
pmb.use_inliner_with_threshold(inline_threshold) pmb.use_inliner_with_threshold(inline_threshold)
if pm: if pm:
pm.add(tm.target_data.clone()) pm.add(tm.target_data.clone())
pm.add(TargetLibraryInfo.new(tm.triple)) pm.add(TargetLibraryInfo.new(tm.triple))
if llvm.version <= (3, 2): if llvm.version >= (3, 2):
pm.add(TargetTransformInfo.new(tm)) pm.add(TargetTransformInfo.new(tm))
else:
tm.add_analysis_passes(pm)
pmb.populate(pm) pmb.populate(pm)
if fpm: if fpm:
fpm.add(tm.target_data.clone()) fpm.add(tm.target_data.clone())
fpm.add(TargetLibraryInfo.new(tm.triple)) fpm.add(TargetLibraryInfo.new(tm.triple))
if llvm.version <= (3, 2): if llvm.version >= (3, 2):
fpm.add(TargetTransformInfo.new(tm)) fpm.add(TargetTransformInfo.new(tm))
else:
tm.add_analysis_passes(fpm)
pmb.populate(fpm) pmb.populate(fpm)
fpm.initialize()
from collections import namedtuple from collections import namedtuple
return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm) return namedtuple('passmanagers', ['pm', 'fpm'])(pm=pm, fpm=fpm)

View file

@ -1,266 +0,0 @@
import llvm
from llvmpy import api, extra
from io import BytesIO
import contextlib
from llvm.passes import TargetData
#===----------------------------------------------------------------------===
# Enumerations
#===----------------------------------------------------------------------===
BO_BIG_ENDIAN = 0
BO_LITTLE_ENDIAN = 1
# CodeModel
CM_DEFAULT = api.llvm.CodeModel.Model.Default
CM_JITDEFAULT = api.llvm.CodeModel.Model.JITDefault
CM_SMALL = api.llvm.CodeModel.Model.Small
CM_KERNEL = api.llvm.CodeModel.Model.Kernel
CM_MEDIUM = api.llvm.CodeModel.Model.Medium
CM_LARGE = api.llvm.CodeModel.Model.Large
# Reloc
RELOC_DEFAULT = api.llvm.Reloc.Model.Default
RELOC_STATIC = api.llvm.Reloc.Model.Static
RELOC_PIC = api.llvm.Reloc.Model.PIC_
RELOC_DYNAMIC_NO_PIC = api.llvm.Reloc.Model.DynamicNoPIC
def initialize_all():
api.llvm.InitializeAllTargets()
api.llvm.InitializeAllTargetInfos()
api.llvm.InitializeAllTargetMCs()
api.llvm.InitializeAllAsmPrinters()
api.llvm.InitializeAllDisassemblers()
api.llvm.InitializeAllAsmParsers()
def initialize_target(target, noraise=False):
"""Initialize target by name.
It is safe to initialize the same target multiple times.
"""
prefix = 'LLVMInitialize'
postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter', 'AsmParser']
try:
for postfix in postfixes:
getattr(api, '%s%s%s' % (prefix, target, postfix))()
except AttributeError:
if noraise:
return False
else:
raise
else:
return True
def print_registered_targets():
'''
Note: print directly to stdout
'''
api.llvm.TargetRegistry.printRegisteredTargetsForVersion()
def get_host_cpu_name():
'''return the string name of the host CPU
'''
return api.llvm.sys.getHostCPUName()
def get_default_triple():
'''return the target triple of the host in str-rep
'''
return api.llvm.sys.getDefaultTargetTriple()
class TargetMachine(llvm.Wrapper):
@staticmethod
def new(triple='', cpu='', features='', opt=2, cm=CM_DEFAULT,
reloc=RELOC_DEFAULT):
if not triple:
triple = get_default_triple()
if not cpu:
cpu = get_host_cpu_name()
with contextlib.closing(BytesIO()) as error:
target = api.llvm.TargetRegistry.lookupTarget(triple, error)
if not target:
raise llvm.LLVMException(error.getvalue())
if not target.hasTargetMachine():
raise llvm.LLVMException(target, "No target machine.")
target_options = api.llvm.TargetOptions.new()
tm = target.createTargetMachine(triple, cpu, features,
target_options,
reloc, cm, opt)
if not tm:
raise llvm.LLVMException("Cannot create target machine")
return TargetMachine(tm)
@staticmethod
def lookup(arch, cpu='', features='', opt=2, cm=CM_DEFAULT,
reloc=RELOC_DEFAULT):
'''create a targetmachine given an architecture name
For a list of architectures,
use: `llc -help`
For a list of available CPUs,
use: `llvm-as < /dev/null | llc -march=xyz -mcpu=help`
For a list of available attributes (features),
use: `llvm-as < /dev/null | llc -march=xyz -mattr=help`
'''
triple = api.llvm.Triple.new()
with contextlib.closing(BytesIO()) as error:
target = api.llvm.TargetRegistry.lookupTarget(arch, triple, error)
if not target:
raise llvm.LLVMException(error.getvalue())
if not target.hasTargetMachine():
raise llvm.LLVMException(target, "No target machine.")
target_options = api.llvm.TargetOptions.new()
tm = target.createTargetMachine(str(triple), cpu, features,
target_options,
reloc, cm, opt)
if not tm:
raise llvm.LLVMException("Cannot create target machine")
return TargetMachine(tm)
@staticmethod
def x86():
return TargetMachine.lookup('x86')
@staticmethod
def x86_64():
return TargetMachine.lookup('x86-64')
@staticmethod
def arm():
return TargetMachine.lookup('arm')
@staticmethod
def thumb():
return TargetMachine.lookup('thumb')
def _emit_file(self, module, cgft):
pm = api.llvm.PassManager.new()
os = extra.make_raw_ostream_for_printing()
pm.add(api.llvm.DataLayout.new(str(self.target_data)))
failed = self._ptr.addPassesToEmitFile(pm, os, cgft)
pm.run(module)
CGFT = api.llvm.TargetMachine.CodeGenFileType
if cgft == CGFT.CGFT_ObjectFile:
return os.bytes()
else:
return os.str()
def emit_assembly(self, module):
'''returns byte string of the module as assembly code of the target machine
'''
CGFT = api.llvm.TargetMachine.CodeGenFileType
return self._emit_file(module._ptr, CGFT.CGFT_AssemblyFile)
def emit_object(self, module):
'''returns byte string of the module as native code of the target machine
'''
CGFT = api.llvm.TargetMachine.CodeGenFileType
return self._emit_file(module._ptr, CGFT.CGFT_ObjectFile)
@property
def target_data(self):
'''get target data of this machine
'''
return TargetData(self._ptr.getDataLayout())
@property
def target_name(self):
return self._ptr.getTarget().getName()
@property
def target_short_description(self):
return self._ptr.getTarget().getShortDescription()
@property
def triple(self):
return self._ptr.getTargetTriple()
@property
def cpu(self):
return self._ptr.getTargetCPU()
@property
def feature_string(self):
return self._ptr.getTargetFeatureString()
@property
def target(self):
return self._ptr.getTarget()
if llvm.version >= (3, 3):
def add_analysis_passes(self, pm):
self._ptr.addAnalysisPasses(pm._ptr)
if llvm.version >= (3, 4):
@property
def reg_info(self):
mri = self._ptr.getRegisterInfo()
if not mri:
raise llvm.LLVMException("no reg info for this machine")
return mri
@property
def subtarget_info(self):
sti = self._ptr.getSubtargetImpl()
if not sti:
raise llvm.LLVMException("no subtarget info for this machine")
return sti
@property
def asm_info(self):
ai = self._ptr.getMCAsmInfo()
if not ai:
raise llvm.LLVMException("no asm info for this machine")
return ai
@property
def instr_info(self):
ii = self._ptr.getInstrInfo()
if not ii:
raise llvm.LLVMException("no instr info for this machine")
return ii
@property
def instr_analysis(self):
if not getattr(self, '_mia', False):
self._mia = self.target.createMCInstrAnalysis(self.instr_info)
if not self._mia:
raise llvm.LLVMException("no instr analysis for this machine")
return self._mia
@property
def disassembler(self):
if not getattr(self, '_dasm', False):
self._dasm = self.target.createMCDisassembler(self.subtarget_info)
if not self._dasm:
raise llvm.LLVMException("no disassembler for this machine")
return self._dasm
@property
def inst_printer(self):
if not getattr(self, '_mip', False):
self._mip = self.target.createMCInstPrinter(
self.asm_info.getAssemblerDialect(),
self.asm_info,
self.instr_info,
self.reg_info,
self.subtarget_info
)
if not self._mip:
raise llvm.LLVMException("no instr printer for this machine")
return self._mip
def is_little_endian(self):
return self.asm_info.isLittleEndian()

1279
llvm/test_llvmpy.py Normal file

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,78 +0,0 @@
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')

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

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

View file

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

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

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

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

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

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

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

View file

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

View file

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

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

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

View file

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

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

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

View file

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

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

View file

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

View file

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

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

View file

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

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

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

View file

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

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

View file

View file

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

View file

@ -12,11 +12,7 @@ http://software.intel.com/sites/default/files/m/a/b/3/4/d/41604-319433-012a.pdf
""" """
import sys import sys, os, subprocess
import os
import subprocess
import contextlib
def detect_avx_support(option='detect'): def detect_avx_support(option='detect'):
'''Detect AVX support''' '''Detect AVX support'''
@ -40,7 +36,6 @@ def detect_unix_like():
except IOError: except IOError:
return False return False
with contextlib.closing(info):
for line in info: for line in info:
if line.lstrip().startswith('flags'): if line.lstrip().startswith('flags'):
features = line.split() features = line.split()
@ -49,17 +44,6 @@ def detect_unix_like():
return True return True
return False return False
@contextlib.contextmanager
def _close_popen(popen):
if sys.version_info[0] >= 3:
with popen:
yield
else:
yield
popen.stdout.close()
def detect_osx_like(): def detect_osx_like():
try: try:
info = subprocess.Popen(['sysctl', '-n', 'machdep.cpu.features'], info = subprocess.Popen(['sysctl', '-n', 'machdep.cpu.features'],
@ -67,8 +51,7 @@ def detect_osx_like():
except OSError: except OSError:
return False return False
with _close_popen(info): features = info.stdout.read()
features = info.stdout.read().decode('UTF8')
features = features.split() features = features.split()
return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features

View file

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

View file

@ -24,98 +24,19 @@
# intp stride; # intp stride;
#} diminfo #} 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 import llvm.core as lc
from llvm.core import Type from llvm.core import Type
import llvm_cbuilder.shortnames as C import llvm_cbuilder.shortnames as C
# Different Array Types CONTIGUOUS = 1 << 8
ARRAYBIT = 1<<4 STRIDED = CONTIGUOUS + 1
C_CONTIGUOUS = ARRAYBIT + 0 STRIDED_SOA = CONTIGUOUS + 2
F_CONTIGUOUS = ARRAYBIT + 1
STRIDED = ARRAYBIT + 2
STRIDED_SOA = ARRAYBIT + 3
HAS_ND = 1<<5 array_kinds = (CONTIGUOUS, STRIDED, STRIDED_SOA)
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 void_type = C.void
int32_type = C.int32 int_type = C.int
char_type = C.char char_type = C.char
int16_type = C.int16 int16_type = C.int16
intp_type = C.intp intp_type = C.intp
@ -124,133 +45,99 @@ diminfo_type = Type.struct([intp_type, # shape
intp_type # stride intp_type # stride
], name='diminfo') ], name='diminfo')
_cache = {}
# This is the way we define LLVM arrays. # This is the way we define LLVM arrays.
# CONTIGUOUS and STRIDED are strongly encouraged... def cont_array_type(nd, el_type=char_type, name=''):
def array_type(nd, kind, el_type=char_type): terms = [Type.pointer(el_type), # data
key = (kind, nd, el_type) Type.array(intp_type, nd) # shape
if _cache.has_key(key): ]
return _cache[key] return Type.struct(terms, name=name)
base = kind & (~(HAS_ND | HAS_DIMKIND)) def strided_array_type(nd, el_type=char_type, name=''):
if base == C_CONTIGUOUS: terms = [Type.pointer(el_type), # data
dimstr = 'Array_C' Type.array(diminfo_type, nd) # diminfo
elif base == F_CONTIGUOUS: ]
dimstr = 'Array_F' return Type.struct(terms, name=name)
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 strided_soa_type(nd, el_type=char_type, name=''):
terms = [Type.pointer(el_type), # data
Type.array(intp_type, nd), # shape[nd]
Type.array(intp_type, nd) # strides[nd]
]
return Type.struct(terms, name=name)
def check_array(arrtyp): def check_array(arrtyp):
if not isinstance(arrtyp, lc.StructType): if not isinstance(arrtyp, lc.StructType):
return None return None
if arrtyp.element_count not in [2, 3, 4, 5]: if arrtyp.element_count not in [2, 3]:
return None
if not isinstance(arrtyp.elements[0], lc.PointerType) or \
not isinstance(arrtyp.elements[1], lc.ArrayType):
return None return None
# Look through _cache and see if it's there data_type = arrtyp.elements[0].pointee
for key, value in _cache.items(): s1 = arrtyp.elements[1]
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 nd = s1.count
if arrtyp.element_count == elcount: if arrtyp.element_count == 3:
if not isinstance(arrtyp.elements[num+1], lc.ArrayType): if not isinstance(arrtyp.elements[2], lc.ArrayType):
return None return None
s2 = arrtyp.elements[num+1] s2 = arrtyp.elements[2]
if s1.element != intp_type or s2.element != intp_type: if s1.element != intp_type or s2.element != intp_type:
return None return None
if s1.count != s2.count: if s1.count != s2.count:
return None return None
return strided_soa, nd, data_type return STRIDED_SOA, nd, data_type
if s1.element == diminfo_type: if s1.element == diminfo_type:
return strided, nd, data_type return STRIDED, nd, data_type
elif s1.element == intp_type: elif s1.element == intp_type:
return c_contiguous if c_contig else f_contiguous, nd, data_type return CONTIGUOUS, nd, data_type
else: else:
return None return None
def is_cont_array(arrtyp):
if not isinstance(arrtyp, lc.StructType):
return False
if arrtyp.element_count != 2 or \
not isinstance(arrtyp.elements[0], lc.PointerType) or \
not isinstance(arrtyp.elements[1], lc.ArrayType):
return False
if arrtyp.elements[1].element != intp_type:
return False
return True
def is_strided_array(arrtyp, kind=diminfo_type):
if not isinstance(arrtyp, lc.StructType):
return False
if arrtyp.element_count != 2 or \
not isinstance(arrtyp.elements[0], lc.PointerType) or \
not isinstance(arrtyp.elements[1], lc.ArrayType):
return False
if arrtyp.elements[1].element != kind:
return False
return True
def is_strided_soa_array(arrtyp):
if not isinstance(arrtyp, lc.StructType):
return False
if arrtyp.element_count != 3 or \
not isinstance(arrtyp.elements[0], lc.PointerType) or \
not isinstance(arrtyp.elements[1], lc.ArrayType) or \
not isinstance(arrtyp.elements[2], lc.ArrayType):
return False
s1, s2 = arrtyp.elements[1:]
if s1.element != intp_type or s2.element != intp_type:
return False
if s1.count != s2.count:
return False
return True
def test(): def test():
arr = array_type(5, C_CONTIGUOUS) arr = cont_array_type(5)
assert check_array(arr) == (C_CONTIGUOUS, 5, char_type) assert check_array(arr) == (CONTIGUOUS, 5, char_type)
arr = array_type(4, STRIDED) arr = strided_array_type(4)
assert check_array(arr) == (STRIDED, 4, char_type) assert check_array(arr) == (STRIDED, 4, char_type)
arr = array_type(3, STRIDED_SOA) arr = strided_soa_type(3)
assert check_array(arr) == (STRIDED_SOA, 3, char_type) assert check_array(arr) == (STRIDED_SOA, 3, char_type)
if __name__ == '__main__': if __name__ == '__main__':

View file

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

5
llvmpy/README Normal file
View file

@ -0,0 +1,5 @@
# 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.

View file

@ -1,151 +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.
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,95 +1,55 @@
#include <Python.h> #include <Python.h>
#include <structmember.h>
#include <python3adapt.h> #include <python3adapt.h>
#include <capsulethunk.h> #include <capsulethunk.h>
#include <llvm_binding/capsule_context.h> #include <llvm_binding/capsule_context.h>
#include <llvm_binding/auto_pyobject.h>
#include <string>
#include <sstream>
static PyObject* TheAPIModule = NULL;
static PyObject* TheCapsuleModule = NULL;
static PyObject* TheCapsuleClass = NULL;
static PyObject* TheWrapperClass = NULL;
static PyObject* TheCache = NULL;
static PyObject* TheAddrDtorDict = NULL;
static PyObject* TheClassesDict = NULL;
static PyObject* TheAddrRefCt = NULL;
static PyObject* ConstantOne = NULL;
static PyObject* TheDowncastModule = NULL;
static static
PyObject* GetAPIModule(){ PyObject* getName(PyObject* self, PyObject* args) {
if (NULL == TheAPIModule) PyObject* obj;
TheAPIModule = PyImport_ImportModule("llvmpy._api"); if (!PyArg_ParseTuple(args, "O", &obj)){
return TheAPIModule; return NULL;
}
const char* name = PyCapsule_GetName(obj);
if (!name) return NULL;
return PyString_FromString(name);
} }
static static
PyObject* GetCapsuleModule(){ PyObject* getPointer(PyObject* self, PyObject* args) {
if (NULL == TheCapsuleModule) PyObject* obj;
TheCapsuleModule = PyImport_ImportModule("llvmpy.capsule"); if (!PyArg_ParseTuple(args, "O", &obj)){
return TheCapsuleModule; return NULL;
}
void* pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj));
if (!pointer) return NULL;
return PyLong_FromVoidPtr(pointer);
} }
static static
PyObject* GetCapsuleClass() { PyObject* check(PyObject* self, PyObject* args) {
if (NULL == TheCapsuleClass) PyObject* obj;
TheCapsuleClass = PyObject_GetAttrString(GetCapsuleModule(), if (!PyArg_ParseTuple(args, "O", &obj)){
"Capsule"); return NULL;
return TheCapsuleClass; }
if (PyCapsule_CheckExact(obj)) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
} }
static // ------------------
PyObject* GetWrapperClass() { // PyCapsule Context
if (NULL == TheWrapperClass) // ------------------
TheWrapperClass = PyObject_GetAttrString(GetCapsuleModule(),
"Wrapper");
return TheWrapperClass;
}
static static
PyObject* GetCache() { CapsuleContext* getContext(PyObject* self, PyObject* args) {
if (NULL == TheCache) PyObject* obj;
TheCache = PyObject_GetAttrString(GetCapsuleModule(), "_cache"); if (!PyArg_ParseTuple(args, "O", &obj)) {
return TheCache; return NULL;
} }
static
PyObject* GetAddrDtorDict() {
if (NULL == TheAddrDtorDict)
TheAddrDtorDict = PyObject_GetAttrString(GetCapsuleModule(),
"_addr2dtor");
return TheAddrDtorDict;
}
static
PyObject* GetClassesDict() {
if (NULL == TheClassesDict)
TheClassesDict = PyObject_GetAttrString(GetCapsuleModule(),
"_pyclasses");
return TheClassesDict;
}
static
PyObject* GetAddrRefCt() {
if (NULL == TheAddrRefCt)
TheAddrRefCt = PyObject_GetAttrString(GetCapsuleModule(),
"_addr2refct");
return TheAddrRefCt;
}
static
PyObject* GetDowncastModule() {
if (NULL == TheDowncastModule)
TheDowncastModule = PyObject_GetAttrString(GetAPIModule(),
"downcast");
return TheDowncastModule;
}
static
CapsuleContext* GetContext(PyObject *obj) {
void* context = PyCapsule_GetContext(obj); void* context = PyCapsule_GetContext(obj);
if (!context) { if (!context) {
PyErr_SetString(PyExc_TypeError, "PyCapsule has no context."); PyErr_SetString(PyExc_TypeError, "PyCapsule has no context.");
@ -99,8 +59,9 @@ CapsuleContext* GetContext(PyObject *obj) {
} }
static static
PyObject* GetClassName(PyObject* obj) { PyObject* getClassName(PyObject* self, PyObject* args) {
CapsuleContext* context = GetContext(obj); CapsuleContext* context = getContext(self, args);
//Assert(context->_magic == 0xdead);
if (!context) { if (!context) {
return NULL; return NULL;
} else { } else {
@ -108,476 +69,6 @@ PyObject* GetClassName(PyObject* obj) {
} }
} }
static
PyObject* getClassName(PyObject* self, PyObject* args) {
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
return GetClassName(obj);
}
static
PyObject* GetName(PyObject* obj) {
const char* name = PyCapsule_GetName(obj);
if (!name) return NULL;
return PyString_FromString(name);
}
static
PyObject* getName(PyObject* self, PyObject* args) {
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj)){
return NULL;
}
return GetName(obj);
}
static
PyObject* GetPointer(PyObject* obj){
void *pointer = PyCapsule_GetPointer(obj, PyCapsule_GetName(obj));
if (!pointer) return NULL;
return PyLong_FromVoidPtr(pointer);
}
static
PyObject* getPointer(PyObject* self, PyObject* args) {
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj)){
return NULL;
}
return GetPointer(obj);
}
static
bool Check(PyObject* obj){
return PyCapsule_CheckExact(obj);
}
static
PyObject* check(PyObject* self, PyObject* args) {
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj)){
return NULL;
}
if (Check(obj)) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
static PyObject* Unwrap(PyObject* obj) {
if (PyObject_IsInstance(obj, GetWrapperClass())) {
return PyObject_GetAttrString(obj, "_ptr");
} else {
Py_INCREF(obj);
return obj;
}
}
/*
Unwrap a Wrapper instance into the underlying PyCapsule.
If `obj` is not a Wrapper instance, returns `obj`.
*/
static PyObject* unwrap(PyObject* self, PyObject* args) {
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
return Unwrap(obj);
}
static bool HasOwnership(PyObject* obj) {
PyObject* addr = GetPointer(obj);
PyObject* name = GetName(obj);
auto_pyobject nameaddr = PyTuple_Pack(2, name, addr);
PyObject* dtor = PyDict_GetItem(GetAddrDtorDict(), *nameaddr);
if (!dtor || dtor == Py_None) {
return false;
} else {
return true;
}
}
static PyObject* has_ownership(PyObject* self, PyObject* args) {
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj)) {
return NULL;
}
if (HasOwnership(obj)) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
static
void NormalizeString(std::ostream &os, const char* str) {
for(; *str; ++str){
if (*str == ':') {
os << '_';
if(*(str + 1) == ':') { ++str; }
} else {
os << *str;
}
}
}
static
PyObject* WrapCore(PyObject *oldCap, bool owned) {
auto_pyobject cap = PyObject_CallFunctionObjArgs(GetCapsuleClass(), oldCap,
NULL);
auto_pyobject cls = PyObject_CallMethod(*cap, "get_class", "");
auto_pyobject addr = GetPointer(oldCap);
auto_pyobject name = GetName(oldCap);
// look up cached object
auto_pyobject cache_cls = PyObject_GetItem(GetCache(), *cls);
Assert(*cache_cls);
int addr_in_cache = PyMapping_HasKey(*cache_cls, *addr);
PyObject* obj = NULL;
if (addr_in_cache) {
obj = PyObject_GetItem(*cache_cls, *addr);
} else {
if (!owned) {
auto_pyobject hasDtor = PyObject_CallMethod(*cls, "_has_dtor", "");
if (PyObject_IsTrue(*hasDtor)) {
auto_pyobject key = PyTuple_Pack(2, *name, *addr);
auto_pyobject val = PyObject_GetAttrString(*cls, "_delete_");
int ok = PyDict_SetItem(GetAddrDtorDict(), *key, *val);
Assert(ok != -1);
}
}
obj = PyObject_CallMethod(*cap, "instantiate", "");
int ok = PyObject_SetItem(*cache_cls, *addr, obj);
Assert(ok != -1);
}
Assert(obj);
return obj;
}
static
PyObject* Wrap(PyObject* cap, bool owned){
if (!Check(cap)) {
if (PyList_Check(cap)) {
const int N = PyList_Size(cap);
PyObject* result = PyList_New(N);
for (int i = 0; i < N; ++i){
PyObject* item = PyList_GetItem(cap, i);
if (!item)
return NULL;
PyObject* out = Wrap(item, false);
if (!out) return NULL;
if (-1 == PyList_SetItem(result, i, out))
return NULL;
}
return result;
} else {
Py_INCREF(cap);
return cap;
}
}
return WrapCore(cap, owned);
}
static
PyObject* wrap(PyObject* self, PyObject* args) {
PyObject* obj;
PyObject* owned = NULL;
if (!PyArg_ParseTuple(args, "O|O", &obj, &owned)) {
return NULL;
}
bool ownedFlag = false;
if (owned) {
ownedFlag = PyObject_IsTrue(owned);
}
return Wrap(obj, ownedFlag);
}
static
PyObject* downcast(PyObject* self, PyObject* args) {
PyObject *obj, *cls;
if (!PyArg_ParseTuple(args, "OO", &obj, &cls)) {
return NULL;
}
auto_pyobject objType = PyObject_Type(obj);
if (*objType == cls) {
Py_INCREF(obj);
return obj;
}
PyObject* apiModule = GetAPIModule();
auto_pyobject fromTy = PyObject_GetAttrString(obj, "_llvm_type_");
auto_pyobject toTy = PyObject_GetAttrString(cls, "_llvm_type_");
std::ostringstream oss;
auto_pyobject fromTyStr = PyObject_Str(*fromTy);
auto_pyobject toTyStr = PyObject_Str(*toTy);
const char * fromCS = PyString_AsString(*fromTyStr);
const char * toCS = PyString_AsString(*toTyStr);
oss << "downcast_";
NormalizeString(oss, fromCS);
oss << "_to_";
NormalizeString(oss, toCS);
std::string fname = oss.str();
auto_pyobject caster = PyObject_GetAttrString(GetDowncastModule(),
fname.c_str());
if (!caster) {
std::ostringstream oss;
oss << "Downcast from " << fromCS << " to " << toCS;
std::string errmsg = oss.str();
PyErr_SetString(PyExc_TypeError, errmsg.c_str());
return NULL;
}
auto_pyobject oldObj = Unwrap(obj);
auto_pyobject newObj = PyObject_CallFunctionObjArgs(*caster, *oldObj,
NULL);
bool used_to_own = HasOwnership(*oldObj);
PyObject *result = Wrap(*newObj, !used_to_own);
int status = PyObject_Not(result);
switch(status) {
case 0:
return result;
case 1:
default:
PyErr_SetString(PyExc_ValueError, "Downcast failed");
Py_XDECREF(result);
return NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
struct CapsuleObject {
PyObject_HEAD;
PyObject *capsule;
};
static
void Capsule_dealloc(CapsuleObject* self) {
Py_XDECREF(self->capsule);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static
int Capsule_init(CapsuleObject *self, PyObject *args, PyObject *kwds)
{
PyObject *cap;
if (!PyArg_ParseTuple(args, "O", &cap)) {
return -1;
}
if (!Check(cap)) {
PyErr_SetString(PyExc_TypeError, "Expected PyCapsule object");
return -1;
}
Py_INCREF(cap);
self->capsule = cap;
PyObject* addr2refct = GetAddrRefCt();
auto_pyobject ptr = GetPointer(self->capsule);
auto_pyobject refct = PyObject_GetItem(addr2refct, *ptr);
auto_pyobject inc = PyNumber_InPlaceAdd(*refct, ConstantOne);
return PyObject_SetItem(addr2refct, *ptr, *inc);
}
static
PyObject* Capsule_getclassname(CapsuleObject* self, void *closure) {
return GetClassName(self->capsule);
}
static
PyObject* Capsule_getname(CapsuleObject* self, void *closure) {
return GetName(self->capsule);
}
static
PyObject* Capsule_getpointer(CapsuleObject* self, void *closure) {
return GetPointer(self->capsule);
}
static
PyObject* Capsule_GetClass(CapsuleObject *self){
PyObject *pycls = GetClassesDict();
auto_pyobject key = GetClassName(self->capsule);
return PyDict_GetItem(pycls, *key); // borrowed reference
}
static
PyObject* Capsule_get_class(CapsuleObject* self, PyObject* args) {
PyObject* out = Capsule_GetClass(self);
Py_XINCREF(out);
return out;
}
static
PyObject* Capsule_instantiate(CapsuleObject* self, PyObject* args) {
return PyObject_CallFunctionObjArgs(Capsule_GetClass(self), self, NULL);
}
/// Rotate Right
static unsigned long RotR(unsigned long hash, int offset){
if (offset == 0) return hash;
unsigned long out = hash << (sizeof(hash) * 8 - offset);
out |= hash >> offset;
return out;
}
/*
This is called everytime an object is returned from LLVM.
It derserves to be optimized to reduce unnecessary Python object allocation.
The following implements a simple hash function that uses XOR and
right-rotation.
*/
static
long Capsule_hash(CapsuleObject *self) {
const char* name = PyCapsule_GetName(self->capsule);
void *pointer = PyCapsule_GetPointer(self->capsule, name);
unsigned long hash = 0xabcd1234 ^ (unsigned long)pointer;
// The first loop accounts for the different LLVM class name and the
// length of the name.
for(const char* p = name; *p != '\0'; ++p) {
hash ^= *p;
hash = RotR(hash, 11);
}
// The second loop accounts for the pointer identity.
for(int i = 0; i <sizeof(pointer); ++i) {
hash ^= ((unsigned char*)&pointer)[i];
hash = RotR(hash, 11);
}
return hash;
}
static
bool Capsule_eq(PyObject *self, PyObject *other) {
if (PyObject_Type(self) == PyObject_Type(other)) {
CapsuleObject *a = (CapsuleObject*)self;
CapsuleObject *b = (CapsuleObject*)other;
void* pa = PyCapsule_GetPointer(a->capsule,
PyCapsule_GetName(a->capsule));
void* pb = PyCapsule_GetPointer(b->capsule,
PyCapsule_GetName(b->capsule));
return pa == pb;
}
return false;
}
static
PyObject* Capsule_richcmp(PyObject *a, PyObject *b, int op) {
bool ret = Capsule_eq(a, b);
switch(op) {
case Py_EQ: break;
case Py_NE: ret = !ret; break;
default:
return Py_NotImplemented;
}
if (ret) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
}
static PyMemberDef Capsule_members[] = {
{"capsule", T_OBJECT_EX, offsetof(CapsuleObject, capsule), READONLY, "capsule"},
{ NULL },
};
static PyMethodDef Capsule_methods[] = {
{ "get_class", (PyCFunction)Capsule_get_class, METH_NOARGS,
"Get Capsule class"},
{ "instantiate", (PyCFunction)Capsule_instantiate, METH_NOARGS,
"create a new instance"},
{ NULL },
};
static PyGetSetDef Capsule_getseters[] = {
{"classname", (getter)Capsule_getclassname, NULL, "class name", NULL},
{"name", (getter)Capsule_getname, NULL, "name", NULL},
{"pointer", (getter)Capsule_getpointer, NULL, "pointer", NULL},
{ NULL },
};
static PyTypeObject CapsuleType = {
#if (PY_MAJOR_VERSION < 3)
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
#else
PyVarObject_HEAD_INIT(NULL, 0)
#endif
"_capsule.Capsule", /*tp_name*/
sizeof(CapsuleObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)Capsule_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)Capsule_hash, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"Capsule object", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
(richcmpfunc)Capsule_richcmp, /*tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Capsule_methods, /* tp_methods */
Capsule_members, /* tp_members */
Capsule_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Capsule_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
///////////////////////////////////////////////////////////////////////////////
static PyMethodDef core_methods[] = { static PyMethodDef core_methods[] = {
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL } #define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
@ -585,10 +76,6 @@ static PyMethodDef core_methods[] = {
declmethod(getPointer), declmethod(getPointer),
declmethod(check), declmethod(check),
declmethod(getClassName), declmethod(getClassName),
declmethod(unwrap),
declmethod(wrap),
declmethod(has_ownership),
declmethod(downcast),
{ NULL }, { NULL },
#undef declmethod #undef declmethod
}; };
@ -619,21 +106,10 @@ extern "C" {
#else #else
PyObject *module = Py_InitModule("_capsule", core_methods); PyObject *module = Py_InitModule("_capsule", core_methods);
#endif #endif
if (module == NULL){ if (module == NULL)
INITERROR; INITERROR;
}
if (module) {
CapsuleType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CapsuleType) < 0) {
INITERROR;
}
Py_INCREF(&CapsuleType);
PyModule_AddObject(module, "Capsule", (PyObject*)(&CapsuleType));
ConstantOne = PyInt_FromLong(1);
}
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
return module; return module;
#endif #endif
} }

View file

@ -1,27 +1,17 @@
from weakref import WeakValueDictionary from weakref import WeakKeyDictionary, WeakValueDictionary, ref
from collections import defaultdict from collections import defaultdict
import logging import logging
from llvmpy._capsule import (unwrap, has_ownership, downcast, wrap,
getClassName, getName, getPointer, Capsule)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
NO_DEBUG = False
def silent_logger(): def silent_logger():
''' '''
Silent logger for unless we have a error message. Silent logger for unless we have a error message.
''' '''
global NO_DEBUG
logger.setLevel(logging.ERROR) logger.setLevel(logging.ERROR)
NO_DEBUG = True
# comment out the line below to re-enable logging at DEBUG level. # comment out the line below to re-enable logging at DEBUG level.
silent_logger() silent_logger()
def set_debug(enabled): def set_debug(enabled):
''' '''
Side-effect: configure logger with it is not configured. Side-effect: configure logger with it is not configured.
@ -36,63 +26,75 @@ 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 = {}
@ -100,13 +102,12 @@ _pyclasses = {}
# NOTE: The same 'addr' may appear in multiple class bins. # NOTE: The same 'addr' may appear in multiple class bins.
_cache = defaultdict(WeakValueDictionary) _cache = defaultdict(WeakValueDictionary)
def release_ownership(old): def release_ownership(old):
logger.debug('Release %s', old) logger.debug('Release %s', old)
addr = getPointer(old) addr = Capsule.getPointer(old)
name = getName(old) name = Capsule.getName(old)
if _addr2dtor.get((name, addr)) is None: if _addr2dtor.get((name, addr)) is None:
clsname = getClassName(old) clsname = Capsule.getClassName(old)
if not _pyclasses[clsname]._has_dtor(): if not _pyclasses[clsname]._has_dtor():
return return
# Guard duplicated release # Guard duplicated release
@ -119,86 +120,60 @@ def obtain_ownership(cap):
if cls._has_dtor(): if cls._has_dtor():
addr = cap.pointer addr = cap.pointer
name = cap.name name = cap.name
assert _addr2dtor[(name, addr)] is None assert _addr2dtor[addr] is None
_addr2dtor[(name, addr)] = cls._delete_ _addr2dtor[(name, addr)] = cls._delete_
def has_ownership(cap):
addr = Capsule.getPointer(cap)
name = Capsule.getName(cap)
return _addr2dtor.get((name, addr)) is not None
#def has_ownership(cap): def wrap(cap, owned=False):
# addr = Capsule.getPointer(cap) '''Wrap a PyCapsule with the corresponding Wrapper class.
# name = Capsule.getName(cap) If `cap` is not a PyCapsule, returns `cap`
# return _addr2dtor.get((name, addr)) is not None '''
if not Capsule.valid(cap):
if isinstance(cap, list):
return list(map(wrap, cap))
return cap # bypass if cap is not a PyCapsule and not a list
cap = Capsule(cap)
cls = cap.get_class()
addr = cap.pointer
name = cap.name
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 wrap(cap, owned=False): def unwrap(obj):
# '''Wrap a PyCapsule with the corresponding Wrapper class.
# If `cap` is not a PyCapsule, returns `cap`
# '''
# if not Capsule.valid(cap):
# if isinstance(cap, list):
# return list(map(wrap, cap))
# return cap # bypass if cap is not a PyCapsule and not a list
#
# cap = Capsule(cap)
# cls = cap.get_class()
# addr = cap.pointer
# name = cap.name
# # lookup cached object
# if cls in _cache and addr in _cache[cls]:
# obj = _cache[cls][addr]
# else:
# if not owned and cls._has_dtor():
# _addr2dtor[(name, addr)] = cls._delete_
# obj = cap.instantiate()
# _cache[cls][addr] = obj # cache it
# return obj
#def unwrap(obj):
'''Unwrap a Wrapper instance into the underlying PyCapsule. '''Unwrap a Wrapper instance into the underlying PyCapsule.
If `obj` is not a Wrapper instance, returns `obj`. If `obj` is not a Wrapper instance, returns `obj`.
''' '''
# if isinstance(obj, Wrapper): if isinstance(obj, Wrapper):
# return obj._ptr return obj._ptr
# else: else:
# return obj return obj
def register_class(clsname): def register_class(clsname):
def _wrapped(cls): def _wrapped(cls):
_pyclasses[clsname] = cls _pyclasses[clsname] = cls
return cls return cls
return _wrapped return _wrapped
class Wrapper(object): class Wrapper(object):
__slots__ = '__capsule' __slots__ = '__capsule'
def __init__(self, capsule): def __init__(self, capsule):
self.__capsule = capsule self.__capsule = capsule
def __del__(self):
if _addr2refct is None:
# System is tearing down
# No need to free anything
return
item = self.__capsule
addr = item.pointer
name = item.name
_addr2refct[addr] -= 1
refct = _addr2refct[addr]
assert refct >= 0, "RefCt drop below 0"
if refct == 0:
dtor = _addr2dtor.pop((name, addr), None)
if dtor is not None:
if not NO_DEBUG:
# Some globals in logger could be removed by python GC
# at interpreter teardown.
# That can cause exception raised and ignored message.
logger.debug('Destroy %s %s', name, hex(addr))
dtor(item.capsule)
@property @property
def _capsule(self): def _capsule(self):
return self.__capsule return self.__capsule
@ -211,11 +186,10 @@ class Wrapper(object):
return hash(self._capsule) return hash(self._capsule)
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, Wrapper):
return self._capsule == other._capsule return self._capsule == other._capsule
def __ne__(self, other): def __ne__(self, other):
return not (self == other) return not(self == other)
def _downcast(self, newcls): def _downcast(self, newcls):
return downcast(self, newcls) return downcast(self, newcls)
@ -224,25 +198,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,4 +1,5 @@
import inspect, textwrap import inspect, textwrap
import functools
import codegen as cg import codegen as cg
import os import os
@ -7,12 +8,10 @@ namespaces = {}
RESERVED = frozenset(['None']) RESERVED = frozenset(['None'])
def makedir(directory): def makedir(directory):
if not os.path.exists(directory): if not os.path.exists(directory):
os.makedirs(directory) os.makedirs(directory)
class SubModule(object): class SubModule(object):
def __init__(self): def __init__(self):
self.methods = [] self.methods = []
@ -248,8 +247,7 @@ 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 = getattr(defn, '_name_', defn.__name__) self.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)
@ -294,10 +292,6 @@ class Class(SubModule, _Type):
writer.println('@capsule.register_class("%s")' % self.fullname) writer.println('@capsule.register_class("%s")' % self.fullname)
with writer.block('class %(clsname)s(%(bases)s):' % locals()): with writer.block('class %(clsname)s(%(bases)s):' % locals()):
writer.println('_llvm_type_ = "%s"' % self.fullname) writer.println('_llvm_type_ = "%s"' % self.fullname)
if self.bases:
writer.println('__slots__ = ()')
else:
writer.println('__slots__ = "__weakref__"')
for enum in self.enums: for enum in self.enums:
enum.compile_py(writer) enum.compile_py(writer)
for meth in self.methods: for meth in self.methods:
@ -338,7 +332,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 = 'unwrap_as<%(ty)s, %(name)s >::from(%(raw)s)' fmt = 'typecast< %(ty)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
@ -404,7 +398,6 @@ class Enum(object):
writer.println(fmt % locals()) writer.println(fmt % locals())
writer.println() writer.println()
class Method(object): class Method(object):
_kind_ = 'meth' _kind_ = 'meth'
@ -522,7 +515,6 @@ class Method(object):
with writer.block('if len(%s) > %d:' % (unwrapped, i)): with writer.block('if len(%s) > %d:' % (unwrapped, i)):
writer.release_ownership('%s[%d]' % (unwrapped, i)) writer.release_ownership('%s[%d]' % (unwrapped, i))
class CustomMethod(Method): class CustomMethod(Method):
def __init__(self, methodname, retty, *argtys): def __init__(self, methodname, retty, *argtys):
super(CustomMethod, self).__init__(retty, *argtys) super(CustomMethod, self).__init__(retty, *argtys)
@ -601,7 +593,6 @@ class CustomFunction(Function):
def fullname(self): def fullname(self):
return self.realname return self.realname
class Destructor(Method): class Destructor(Method):
_kind_ = 'dtor' _kind_ = 'dtor'
@ -633,7 +624,6 @@ class Constructor(StaticMethod):
ret = writer.declare(retty.fullname, stmt) ret = writer.declare(retty.fullname, stmt)
return ret return ret
class ref(_Type): class ref(_Type):
def __init__(self, element): def __init__(self, element):
assert isinstance(element, Class), type(element) assert isinstance(element, Class), type(element)
@ -695,16 +685,13 @@ class ptr(_Type):
return writer.pycapsule_new(val, self.element.capsule_name, return writer.pycapsule_new(val, self.element.capsule_name,
self.element.fullname) self.element.fullname)
class ownedptr(ptr): class ownedptr(ptr):
pass pass
def const(ptr_or_ref): def const(ptr_or_ref):
ptr_or_ref.const = True ptr_or_ref.const = True
return ptr_or_ref return ptr_or_ref
class cast(_Type): class cast(_Type):
format = 'O' format = 'O'
@ -769,7 +756,6 @@ class CustomPythonMethod(object):
for line in self.sourcelines: for line in self.sourcelines:
writer.println(line) writer.println(line)
class CustomPythonStaticMethod(CustomPythonMethod): class CustomPythonStaticMethod(CustomPythonMethod):
def compile_py(self, writer): def compile_py(self, writer):
writer.println('@staticmethod') writer.println('@staticmethod')
@ -858,7 +844,6 @@ class Attr(object):
TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split() TARGETS_BUILT = os.environ.get('LLVM_TARGETS_BUILT', '').split()
def _parse_llvm_version(ver): def _parse_llvm_version(ver):
import re import re
m = re.compile(r'(\d+)\.(\d+)').match(ver) m = re.compile(r'(\d+)\.(\d+)').match(ver)

View file

@ -202,8 +202,7 @@ 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)
cast_to_base = 'cast_to_base<%s >::from(%s)' % (name, ptr) ret = self.call('pycapsule_new', 'PyObject*', ptr, quote(name),
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)
PyMODINIT_FUNC PyObject *
PyInit_%(module)s(void) PyInit_%(module)s(void)
{ {
PyObject *module = create_python_module("%(module)s", meth_%(ns)s); PyObject *module = create_python_module("%(module)s", meth_%(ns)s);

View file

@ -256,7 +256,6 @@ 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);
} }
@ -266,24 +265,3 @@ 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,26 +1,8 @@
#include <Python.h> #include <Python.h>
#include <llvm/ADT/SmallVector.h> #include <llvm/ADT/SmallVector.h>
#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3 #include <llvm/Value.h>
#include <llvm/IR/Value.h> #include <llvm/DerivedTypes.h>
#include <llvm/IR/DerivedTypes.h> #include <llvm/Function.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>
@ -30,11 +12,14 @@
#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"
@ -71,15 +56,6 @@ 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)
{ {
@ -186,8 +162,8 @@ PyObject* iterator_to_pylist_deref(iterator begin, iterator end,
{ {
PyObject* list = PyList_New(0); PyObject* list = PyList_New(0);
for(; begin != end; ++begin) { for(; begin != end; ++begin) {
auto_pyobject cap = pycapsule_new(&*begin, capsuleName, className); PyObject* cap = pycapsule_new(&*begin, capsuleName, className);
PyList_Append(list, *cap); PyList_Append(list, cap);
} }
return list; return list;
} }
@ -198,8 +174,8 @@ PyObject* iterator_to_pylist(iterator begin, iterator end,
{ {
PyObject* list = PyList_New(0); PyObject* list = PyList_New(0);
for(; begin != end; ++begin) { for(; begin != end; ++begin) {
auto_pyobject cap = pycapsule_new(*begin, capsuleName, className); PyObject* cap = pycapsule_new(*begin, capsuleName, className);
PyList_Append(list, *cap); PyList_Append(list, cap);
} }
return list; return list;
} }
@ -294,12 +270,7 @@ llvm::ExecutionEngine* ExecutionEngine_create(
ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter, ExecutionEngine *ee = ExecutionEngine::create(M, ForceInterpreter,
&ErrorStr, OptLevel, &ErrorStr, OptLevel,
GVsWithCode); GVsWithCode);
auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); PyFile_WriteString(ErrorStr.c_str(), errout);
if (errout && NULL == callwrite(errout, *buf)){
return NULL;
}
// PyFile_WriteString(ErrorStr.c_str(), errout);
return ee; return ee;
} }
@ -321,11 +292,7 @@ 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);
auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); PyFile_WriteString(ErrorStr.c_str(), errout);
if (errout && NULL == callwrite(errout, *buf)){
return NULL;
}
// PyFile_WriteString(ErrorStr.c_str(), errout);
return ee; return ee;
} }
@ -507,7 +474,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 == callwrite(FObj, *buf)){ if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){
return NULL; return NULL;
} }
// if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { // if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
@ -531,7 +498,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 callwrite(FObj, *buf); return PyObject_CallMethod(FObj, "write", "O", *buf);
} }
static static
@ -545,13 +512,9 @@ 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);
auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) {
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);
} }
@ -575,11 +538,11 @@ PyObject* TargetMachine_addPassesToEmitFile(
bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify); bool status = TM->addPassesToEmitFile(PM, fso, FTy, disableVerify);
if (status) { if (status) {
StringRef sr = rso.str(); StringRef sr = rso.str();
auto_pyobject buf = PyString_FromStringAndSize(sr.data(), sr.size()); PyObject* buf = PyString_FromStringAndSize(sr.data(), sr.size());
if (!buf) { if (!buf) {
return NULL; return NULL;
} }
if (-1 == PyFile_WriteObject(*buf, Out, Py_PRINT_RAW)){ if (-1 == PyFile_WriteObject(buf, Out, Py_PRINT_RAW)){
return NULL; return NULL;
} }
Py_RETURN_TRUE; Py_RETURN_TRUE;
@ -618,17 +581,11 @@ 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;
@ -646,13 +603,9 @@ PyObject* Linker_LinkModules(llvm::Module* Dest,
if (! failed) { if (! failed) {
Py_RETURN_FALSE; Py_RETURN_FALSE;
} else { } else {
auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
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;
} }
} }
@ -712,14 +665,9 @@ 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) {
auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
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;
@ -842,13 +790,9 @@ 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) {
auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) {
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);
@ -861,27 +805,6 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename,
} }
} }
static
PyObject* DynamicLibrary_getPermanentLibrary(const char * Filename,
PyObject* ErrMsg = 0)
{
using namespace llvm::sys;
std::string errmsg;
DynamicLibrary dylib = DynamicLibrary::getPermanentLibrary(Filename, &errmsg);
if (!dylib.isValid()) {
if (ErrMsg) {
auto_pyobject buf = PyBytes_FromString(errmsg.c_str());
if (!callwrite(ErrMsg, *buf))
return NULL;
}
PyErr_SetString(PyExc_RuntimeError, errmsg.c_str());
return NULL;
}
return pycapsule_new(new DynamicLibrary(dylib),
"llvm::sys::DynamicLibrary",
"llvm::sys::DynamicLibrary");
}
class PassRegistryEnumerator : public llvm::PassRegistrationListener{ class PassRegistryEnumerator : public llvm::PassRegistrationListener{
public: public:
PyObject* List; PyObject* List;
@ -891,8 +814,7 @@ public:
inline virtual void passEnumerate(const llvm::PassInfo * pass_info){ inline virtual void passEnumerate(const llvm::PassInfo * pass_info){
PyObject* passArg = PyString_FromString(pass_info->getPassArgument()); PyObject* passArg = PyString_FromString(pass_info->getPassArgument());
PyObject* passName = PyString_FromString(pass_info->getPassName()); PyObject* passName = PyString_FromString(pass_info->getPassName());
auto_pyobject pair = Py_BuildValue("(OO)", passArg, passName); PyList_Append(List, Py_BuildValue("(OO)", passArg, passName));
PyList_Append(List, *pair);
} }
}; };
@ -913,12 +835,7 @@ 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");
@ -935,18 +852,14 @@ 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)
{ {
@ -954,12 +867,7 @@ 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) {
auto_pyobject buf = PyBytes_FromString(error.c_str()); PyFile_WriteString(error.c_str(), Error);
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");
@ -967,66 +875,6 @@ 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)
{ {
@ -1050,23 +898,3 @@ 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', 'all-targets' 'linker', 'support', 'vectorize',
] ]
nvptx = ['nvptx', nvptx = ['nvptx',

Some files were not shown because too many files have changed in this diff Show more